가장 빠른 알고리즘 최적화 과제


9

시간 복잡성에 대한 설명이 제공되는 한 코드 전체의 답변에 만족하지만, 이것은 점근 적 복잡성 문제에 대한 첫 번째 실험입니다.

다음과 같은 문제가 있습니다.

작업 T_1, ... T_n 및 procs M_1, ..., M_m을 고려하십시오. 각 작업은 프로세스에 따라 특정 시간이 걸립니다.

각 작업은 또한 procs에 따라 수행 할 일정 비용이 든다.

작업은 엄격한 순서로 수행해야하며 (병렬로 수행 할 수 없음) proc을 변경하는 데 시간이 걸립니다. 작업을 시작한 후에는 한 프 로세스에서 다른 프 로로 이동할 수 없습니다.

마지막으로 각 작업은 특정 시간까지 완료해야합니다.

작업

목표는 위 양식의 5 개 테이블이 제공된 알고리즘 (또는 일부 코드)을 제공하여 모든 작업을 완료하는 데 필요한 총 비용을 최소화하면서 마감일까지 모든 작업을 완료하는 것입니다. 이것이 가능하지 않다면 우리는 그것을 할 수 없다고보고합니다.

점수

변수 n, m 및 d의 관점에서 솔루션의 복잡도를 크게 지정해야합니다. 여기서 d는 최종 기한입니다. 큰 Oh 복잡성에는 불필요한 상수가 없어야합니다. 따라서 O (n / 1000)은 예를 들어 O (n)으로 작성해야합니다.

점수는 명시된 복잡도로 n = 100, m = 100 및 d = 1000을 설정하여 간단히 계산됩니다. 가능한 가장 작은 점수를 원합니다.

타이 브레이커

동점 인 경우 첫 번째 답이 이깁니다.


추가 된 메모

log 시간이 지남에 따라 답이 복잡해집니다.

스코어 보드

  • KSFT ( Python )의 10 ^ 202 먼저 제출하여 현상금을 얻습니다.
  • Dominik Müller ( 스칼라 )의 10 ^ 202

"행 기계에서 열 기계로 전환 시간"M_1에서 M_2로 전환하는 데 시간이 걸리는 것을 의미합니까? 또한 "전환 비용"과 "전환 시간"의 차이점은 무엇입니까? 그것들은 일반적으로 스케줄링 알고리즘을 설명하는 것과 같은 것을 의미합니다.
Luminous

@Luminous 시간을 초 단위로 생각하고 비용은 달러 단위입니다. 그들은이 질문에서 다른 것들입니다. 다음 표는 다음 작업을 수행하기 위해 기계를 교체하는 시간 (각각의 비용)을 보여줍니다. M_1에서 M_2 또는 M_2에서 M_1 일 수 있습니다.

알았어요.
Luminous

짧은 대답은 복잡성이 될 것이라는 것 O(m ^ n)입니다. 그보다 더 빠른 알고리즘은 없습니다. 필요한 최대 시간 또는 비용을 기준으로 잘라내는 것은 알고리즘의 복잡성을 변경하지 않으며 달러 비용과 시간 비용을 모두 가지지 않으므로 d복잡성의 요소가 아닙니다.
Bob Dalgleish

1
@BobDalgleish 그것은 100의 거듭 제곱에 100 점을줍니다. 나는 당신이 훨씬 더 잘할 수 있다고 믿습니다.

답변:


2

점수 : 10 ^ 202

LaTeX 지원을 받으 셨으면합니다 ...

아무도 대답하지 않았기 때문에 매우 효율적이지 않지만 시도 할 것이라고 생각했습니다. 그래도 큰 O가 무엇인지 잘 모르겠습니다.

나는 그것이 작동한다고 생각합니다. 적어도 게시 된 유일한 테스트 사례에 대해서는 해당됩니다.

기계 또는 작업 번호 레이블이없고 줄 바꿈 대신 세미콜론이있는 것을 제외하고는 질문과 같이 입력이 필요합니다.

import itertools
time = [[int(j) for j in i.split()] for i in raw_input().split(";")]
cost = [[int(j) for j in i.split()] for i in raw_input().split(";")]
nmachines=len(time)
ntasks=len(time[0])
switchtime = [[int(j) for j in i.split()] for i in raw_input().split(";")]
switchcost = [[int(j) for j in i.split()] for i in raw_input().split(";")]
deadline = [int(i) for i in raw_input().split()]
d={}
m=itertools.product(range(nmachines),repeat=ntasks)
for i in m:
    t=-switchtime[i[-1]][i[0]]
    c=-switchcost[i[-1]][i[0]]
    e=0
    meetsdeadline=True
    for j in range(ntasks):
        t+=switchtime[i[e-1]][i[e]]+time[i[e]][j]
        c+=switchcost[i[e-1]][i[e]]+cost[i[e]][j]
        e+=1
        if t>deadline[j]:
            meetsdeadline=False
    if meetsdeadline:
        d[(c,t)]=i
print min(d.keys()),d[min(d.keys())]

몇 가지 설명을 제공하고 점수에 대한 느낌을 말할 수 있습니까? 또한 질문의 예에서 무엇을 제공하는지 보여 줄 수 있습니까?

내 대답에 언급했듯이 시도해 보았으며 예제에서 작동합니다. 큰 O가 무엇인지 잘 모르겠습니다 (내 대답에서 언급하려고 함).
KSFT

기본적으로 대략 몇 개의 작업을 완료해야합니까? ntasks * m 시간이 거의 걸리는 것처럼 보입니다 (루프의 모든 할당에 일정한 시간이 걸리는 것으로 가정). 왜 그것이 효과가 있다고 생각하는지에 대해 말할 수 있습니까?

1
오! 나는 그것을 놓쳤다. 따라서 m은 실제로 nmachines ^ ntasks 크기입니다. 이제는 작동한다고 생각합니다. 귀하의 점수는 (100 ^ 100) * 100입니다.

4
@Lembik 지금까지 최고 점수를 받았습니다!
KSFT

1

모두 확인-스칼라

예상 점수 : 2m ^ n

각 컴퓨터에서 시작하여 모든 작업을 반복하여 마감 시간을 충족시키는 다른 컴퓨터의 작업을 통해 모든 순열을 만듭니다. 모든 것이 제 시간에 있다면 2 개의 기계와 3 개의 작업으로 9 개의 가능한 경로를 얻을 수 있습니다. (m ^ n) 그 후 가장 저렴한 비용으로 길을갑니다.

입력은 다음과 같이 구성됩니다 (-> 부분을 설명하므로 입력해서는 안 됨).

M_1:5 3 5 4;M_2:4 2 7 5                 --> time
M_1:5 4 2 6;M_2:3 7 3 3                 --> cost
M_1:M_1}0 M_2}1;M_2:M_1}2 M_2}0         --> switch itme
M_1:M_1}0 M_2}2;M_2:M_1}1 M_2}0         --> switch cost
5 10 15 20                              --> deadlines

그리고 여기 코드가 있습니다 :

package Scheduling

import scala.io.StdIn.readLine

case class Cost(task: Map[String, List[Int]])
case class Switch(machine: Map[String, Map[String, Int]])
case class Path(time: Int, cost: Int, machine: List[String])

object Main {

    def main(args: Array[String]) {
        val (machines, cost_time, cost_money, switch_time, switch_money, deadlines) = getInput

        val s = new Scheduler(machines, cost_time, cost_money, switch_time, switch_money, deadlines)
        s.schedule
    }

    def getInput(): (List[String], Cost, Cost, Switch, Switch, List[Int]) = {
        val cost_time = Cost(readLine("time to complete task").split(";").map{s => 
                val parts = s.split(":")
                (parts(0) -> parts(1).split(" ").map(_.toInt).toList)
            }.toMap)

        val cost_money = Cost(readLine("cost to complete task").split(";").map{s => 
                val parts = s.split(":")
                (parts(0) -> parts(1).split(" ").map(_.toInt).toList)
            }.toMap)

        val switch_time = Switch(readLine("time to switch").split(";").map{s => 
                val parts = s.split(":")
                (parts(0) -> parts(1).split(" ").map{t =>
                        val entries = t.split("}")
                        (entries(0) -> entries(1).toInt)
                    }.toMap)
            }.toMap)

        val switch_money = Switch(readLine("time to switch").split(";").map{s => 
                val parts = s.split(":")
                (parts(0) -> parts(1).split(" ").map{t =>
                        val entries = t.split("}")
                        (entries(0) -> entries(1).toInt)
                    }.toMap)
            }.toMap)

        val deadlines = readLine("deadlines").split(" ").map(_.toInt).toList

        val machines = cost_time.task.keys.toList

        (machines, cost_time, cost_money, switch_time, switch_money, deadlines)
    }
}

class Scheduler(machines: List[String], cost_time: Cost, cost_money: Cost, switch_time: Switch, switch_money: Switch, deadlines: List[Int]) {

    def schedule() {
        var paths = List[Path]()
        var alternatives = List[(Int, Path)]()

        for (i <- machines) {
            if (cost_time.task(i)(0) <= deadlines(0)) {
                paths = paths ::: List(Path(cost_time.task(i)(0), cost_money.task(i)(0), List(i)))
            }
        }

        val allPaths = deadlines.zipWithIndex.tail.foldLeft(paths)((paths, b) => paths.flatMap(x => calculatePath(x, b._1, b._2)))

        if (allPaths.isEmpty) {
            println("It is not possible")
        } else {
            println(allPaths.minBy(p=>p.cost).machine)
        }
    }

    def calculatePath(prev: Path, deadline: Int, task: Int): List[Path] = {
        val paths = machines.map(m => calculatePath(prev, task, m))
        paths.filter(p => p.time <= deadline)
    }

    def calculatePath(prev: Path, task: Int, machine: String): Path = {
        val time = prev.time + switch_time.machine(prev.machine.last)(machine) + cost_time.task(machine)(task)
        val cost = prev.cost + switch_money.machine(prev.machine.last)(machine) + cost_money.task(machine)(task)

        Path(time, cost, prev.machine :+ machine)
    }
}

나는 또한 뒤에서 시작할 생각이 있었다. 시간이 더 작 으면 항상 가장 낮은 비용으로 기계를 선택할 수 있기 때문에 이전 기한과 새 기한의 차이가 다릅니다. 그러나 더 나은 비용의 작업이 마지막 마감 시간보다 오래 걸리더라도 최대 런타임이 줄어들지는 않습니다.

최신 정보

======

또 다른 설정이 있습니다. 시각:

M_1 2 2 2 7
M_2 1 8 5 10

비용:

M_1 4 4 4 4
M_2 1 1 1 1

전환 시간 :

    M_1 M_2
M_1  0   2
M_2  6   0

스위치 비용 :

    M_1 M_2
M_1  0   2
M_2  2   0

마감일 :

5 10 15 20

내 프로그램에 입력으로 :

M_1:2 2 2 7;M_2:1 8 5 10
M_1:4 4 4 4;M_2:1 1 1 1
M_1:M_1}0 M_2}2;M_2:M_1}6 M_2}0
M_1:M_1}0 M_2}2;M_2:M_1}2 M_2}0
5 10 15 20

시간, 18, 비용 : 15, 경로 : List (M_1, M_1, M_1, M_2) 시간 : 18, 비용 : 15, 경로 : List (M_2, M_1, M_1, M_1)

이것이 어떻게 처리되어야하는지에 대한 의문을 제기합니다. 모두 인쇄해야합니까 아니면 하나만 인쇄해야합니까? 시간이 다를 경우 어떻게해야합니까? 비용이 가장 적게 들고 마감 기한이 충분하지 않습니까?


문제는 목표는 "총 비용을 최소화하는 것"이라고 말합니다. 그런데 알고리즘 작동 방식을 요약 할 수 있습니까? 나는 스칼라를 모르며 이것이 어떻게 작동하는지 알 수 없습니다.
KSFT

모든 경로를 반복하는 데 O(m^n)시간 이 걸립니다 . 모든 작업에 대해 각 컴퓨터 반복 하는O(n*m^n)시간 이 걸립니다 .
KSFT

O(n*m^n)각 경로마다 각 작업을 반복 하지 않습니까? 그리고 같은 각 작업에 대해 각 컴퓨터를 반복합니다 O(n*m).
Dominik Müller

아, 오타. " 모든 경로에 대해 각 컴퓨터 반복하는 데 걸리는 시간 O(n*m^n)" 을 쓰려고했습니다 .
KSFT

잠깐만 요 O(m*m^n)=O(m^n+1). 그래도 여전히 같은 점수입니다.
KSFT
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.