最速のアルゴリズム最適化の課題


9

これは、漸近的な複雑さの課題に対する私の最初の実験ですが、時間の複雑さの説明が付いている限り、コードで完全に答えることに満足しています。

次の問題があります。

タスクT_1、... T_nおよびprocs M_1、...、M_mについて考えてみます。各タスクは、プロシージャに応じて、実行に一定の時間がかかります。

各タスクは、procに応じて、実行に一定のコストがかかります。

タスクは厳密な順序で実行する必要があり(並行して実行することはできません)、プロシージャの変更には時間がかかります。開始後、タスクをあるプロシージャから別のプロシージャに移動することはできません。

最後に、各タスクは特定の時間までに完了する必要があります。

タスク

目的は、上記のフォームの5つのテーブルを与え、すべてのタスクを完了するための総コストを最小限に抑えながら、すべてのタスクが期限までに完了することを保証するアルゴリズム(またはコード)を提供することです。これが不可能な場合は、実行できないことを報告します。

スコア

変数n、m、dに関して、ソリューションの大きなOh複雑さを与える必要があります。dは最後の期限です。大きなOhの複雑さには不必要な定数があってはなりません。たとえば、O(n / 1000)はO(n)のように記述します。

スコアは、n = 100、m = 100、d = 1000を設定した複雑度に設定するだけで計算されます。あなたは可能な限り最小のスコアを求めています。

タイ・ブレーカー

引き分けの場合、最初の答えが優先されます。


追加されたメモ

log 時間内に、回答の複雑さは2を基にして計算されます。

スコアボード

  • KSFT(Python)からの10 ^ 202 最初に提出されたので、賞金を獲得します。
  • DominikMüller(Scala)の10 ^ 202

「行マシンから列マシンへの切り替え時間」これは、M_1からM_2への切り替えにかかる時間のコストですか。また、「切り替えコスト」と「切り替え時間」の違いは何ですか。これらは通常、スケジューリングアルゴリズムの説明と同じ意味です。
2015年

@Luminous時間は秒単位で、コストはドル単位で考えてください。この質問では、それらは異なるものです。次の表は、次のタスクを実行するためにマシンを変更する時間(それぞれのコスト)を示しています。これは、M_1からM_2まで、またはM_2からM_1までです。

わかりました。
Luminous

簡単に言えば、複雑さは次のようになりますO(m ^ n)。それより「速い」アルゴリズムはありません。必要な最大時間またはコストに基づく剪定は、アルゴリズムの複雑さを変更せず、ドルコストと時間コストの両方を持つこともないためd、複雑さの要素ではありません。
Bob Dalgleish、2015年

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 2015年

基本的に、完了するまでにかかるおおよその操作回数。概してntasks * m時間がかかるようです(ループ内のすべての割り当てに一定の時間がかかると仮定します)。なぜそれがうまくいくと思うのですか?

1
ああ!私は逃しました。したがって、mは実際にはサイズnmachines ^ ntasksです。OK、私はそれがうまくいくと信じています。あなたのスコアは(100 ^ 100)* 100だと思います。

4
@Lembik今までで最高のスコアです!
KSFT 2015年

1

すべてチェック-Scala

推定スコア: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

これには2つのソリューションがあります:時間:18、コスト:15、パス:List(M_1、M_1、M_1、M_2)時間:18、コスト:15、パス:List(M_2、M_1、M_1、M_1)

これは、これをどのように処理すべきかという問題を提起します。すべて印刷する必要がありますか、それとも1つだけですか?そして、時間が異なる場合はどうなりますか?コストが最も低く、締め切りを逃していないか、それとも時間が最も短いものである必要がありますか?


質問は、目標は「総コストを[最小限に抑える]」であると述べています。ところで、アルゴリズムがどのように機能するかを要約できますか?私はScalaを知りませんが、これがどのように機能するのか理解できません。
KSFT、2015年

すべてのパスを繰り返し処理するにはO(m^n)時間がかかります。すべてのタスクで各マシン繰り返し処理するにO(n*m^n)時間がかかります。
KSFT 2015年

O(n*m^n)各パスの各タスクを繰り返していませんか?そして、各タスクのために各マシンを繰り返しO(n*m)ます。
ドミニクミュラー

あ、タイプミス。私は、「各マシンを反復処理を記述することを意図したすべてのパスのために取りますO(n*m^n)」。
KSFT 2015年

待って、いいえ、それはO(m*m^n)=O(m^n+1)です。ただし、それでもスコアは同じです。
KSFT 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.