ความท้าทายการเพิ่มประสิทธิภาพอัลกอริทึมที่เร็วที่สุด


9

นี่คือการทดลองครั้งแรกของฉันกับความซับซ้อนเชิงซีมโทติคแม้ว่าฉันจะมีความสุขกับคำตอบทั้งหมดในโค้ดตราบใดที่พวกเขามาพร้อมกับคำอธิบายเกี่ยวกับความซับซ้อนของเวลา

ฉันมีปัญหาดังต่อไปนี้

พิจารณางาน T_1, ... T_n และ procs M_1, ... , M_m แต่ละงานใช้เวลาในการดำเนินการตามจำนวนที่กำหนด

แต่ละงานมีค่าใช้จ่ายจำนวนหนึ่งเพื่อดำเนินการขึ้นอยู่กับ procs

งานจะต้องทำในลำดับที่เข้มงวด (พวกเขาไม่สามารถทำได้ในแบบคู่ขนาน) และต้องใช้เวลาในการเปลี่ยนกระบวนการ ไม่สามารถย้ายงานจาก proc หนึ่งไปยังอีก proc หลังจากเริ่มต้น

ในที่สุดงานแต่ละงานจะต้องเสร็จสิ้นตามระยะเวลา

งาน

วัตถุประสงค์คือเพื่อให้อัลกอริทึม (หรือโค้ดบางส่วน) ที่ได้รับห้าตารางของแบบฟอร์มด้านบนลดค่าใช้จ่ายทั้งหมดเพื่อให้งานทั้งหมดเสร็จสมบูรณ์ในขณะที่ทำให้แน่ใจว่างานทั้งหมดจะเสร็จสิ้นตามกำหนดเวลา หากเป็นไปไม่ได้เราเพียงแค่รายงานว่ามันไม่สามารถทำได้

คะแนน

คุณควรให้ความซับซ้อนในการแก้ปัญหาของคุณในรูปของตัวแปร n, m และ d, โดยที่ d คือวันสุดท้าย ไม่ควรมีค่าคงที่ไม่จำเป็นในความซับซ้อนของโอ้ใหญ่ของคุณ ตัวอย่างเช่น O (n / 1,000) ควรเขียนเป็น O (n)

คะแนนของคุณถูกคำนวณอย่างง่าย ๆ โดยการตั้งค่า n = 100, m = 100 และ d = 1,000 ในความซับซ้อนที่คุณระบุไว้ คุณต้องการได้คะแนนน้อยที่สุด

เบรกเกอร์

ในกรณีที่เสมอกันคำตอบแรกจะชนะ


เพิ่มบันทึก

log ในเวลาที่ซับซ้อนของคำตอบจะได้รับฐาน 2

กระดานคะแนน

  • 10 ^ 202 จาก KSFT ( Python ) ส่งครั้งแรกเพื่อรับรางวัล
  • 10 ^ 202 จาก Dominik Müller ( Scala )

"เปลี่ยนเวลาจากเครื่องแถวเป็นเครื่องคอลัมน์" คุณหมายถึงเวลาที่ต้องเปลี่ยนจาก M_1 เป็น M_2 หรือไม่ นอกจากนี้ความแตกต่างระหว่าง "ต้นทุนการสลับ" และ "เวลาเปลี่ยน" คืออะไร โดยทั่วไปแล้วพวกเขาหมายถึงสิ่งเดียวกันในการอธิบายขั้นตอนวิธีการตั้งเวลา
ส่องสว่าง

@Luminous ลองนึกถึงเวลาในไม่กี่วินาทีและคิดราคาเป็นดอลลาร์ พวกเขาต่างกันในคำถามนี้ ตารางแสดงเวลา (ค่าใช้จ่ายตามลำดับ) ของการเปลี่ยนเครื่องเพื่อทำงานต่อไป ซึ่งอาจมาจาก M_1 ถึง M_2 หรือจาก M_2 ถึง M_1

ตกลงว่าชัดเจน
การส่องสว่าง

คำตอบสั้น ๆ ก็คือความซับซ้อนจะเป็นO(m ^ n)อย่างไร ไม่มีอัลกอริทึมจะ "เร็ว" กว่านั้น การตัดแต่งตามเวลาหรือค่าใช้จ่ายสูงสุดที่กำหนดจะไม่เปลี่ยนความซับซ้อนของอัลกอริทึมและไม่มีทั้งค่าเงินดอลลาร์และค่าใช้จ่ายเวลาดังนั้นจึงdไม่ใช่องค์ประกอบของความซับซ้อน
Bob Dalgleish

1
@ BobDalgleish ที่ให้คะแนน 100 ถึงพลัง 100 ฉันเชื่อว่าคุณทำได้ดีกว่านี้มาก

คำตอบ:


2

คะแนน: 10 ^ 202

ฉันหวังว่าเราจะได้รับการสนับสนุนจาก LaTeX ...

เนื่องจากไม่มีใครตอบฉันคิดว่าฉันจะลองแม้ว่าจะไม่ได้ผล ฉันไม่แน่ใจว่าโอใหญ่ของมันคืออะไร

ฉันคิดว่ามันใช้งานได้ อย่างน้อยมันก็ทำสำหรับกรณีทดสอบเฉพาะโพสต์

มันจะใส่เหมือนในคำถามยกเว้นไม่มีป้ายชื่อเครื่องหรืองานและด้วยเครื่องหมายอัฒภาคแทนการแบ่งบรรทัด

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())]

คุณสามารถให้คำอธิบายและพูดในสิ่งที่คุณรู้สึกว่าคะแนนของคุณควรเป็นอย่างไร นอกจากนี้คุณสามารถแสดงให้เห็นว่ามันเป็นตัวอย่างในคำถามได้หรือไม่

ตามที่ระบุไว้ในคำตอบของฉันฉันได้ลองแล้วและมันก็ใช้ได้กับตัวอย่าง ฉันไม่แน่ใจว่าโอใหญ่คืออะไร (ซึ่งฉันตั้งใจจะพูดถึงในคำตอบของฉัน)
KSFT

โดยทั่วไปประมาณว่าจะใช้เวลาดำเนินการกี่อย่างเพื่อให้เสร็จสมบูรณ์ ดูเหมือนว่าใช้เวลา ntasks * m ประมาณ (ถือว่าการมอบหมายทั้งหมดในลูปใช้เวลาคงที่) ซึ่งทำให้ฉันสงสัยเกี่ยวกับความถูกต้องของมันที่ฉันต้องยอมรับ คุณช่วยพูดบางอย่างเกี่ยวกับสาเหตุที่คุณคิดว่ามันใช้งานได้

1
Oh! ฉันคิดถึงสิ่งนั้น ดังนั้น m จึงเป็นขนาด nmachines ^ ntasks ตกลงตอนนี้ฉันเชื่อว่ามันใช้งานได้ ฉันคิดว่าคะแนนของคุณคือ (100 ^ 100) * 100

4
@ Lembik มันมีคะแนนที่ดีที่สุดจนถึงตอนนี้!
KSFT

1

ตรวจสอบทั้งหมด - สกาล่า

คะแนนโดยประมาณ: 2m ^ n

ฉันเริ่มจากแต่ละเครื่องและวนซ้ำทุกงานเพื่อสร้างการเรียงสับเปลี่ยนทั้งหมดผ่านงานด้วยเครื่องจักรต่าง ๆ ที่ตรงตามกำหนดเวลา หมายความว่าถ้าทุกอย่างตรงเวลาฉันจะได้ 9 เส้นทางที่เป็นไปได้ด้วย 2 เครื่องและ 3 งาน (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, เส้นทาง: รายการ (M_1, M_1, M_1, M_2) เวลา: 18, ราคา: 15, เส้นทาง: รายการ (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

อ่าพิมพ์ผิด ผมหมายถึงการเขียน "iterating กว่าแต่ละเครื่องสำหรับทุกเส้นทางที่จะใช้เวลาO(n*m^n)"
KSFT

O(m*m^n)=O(m^n+1)รอไม่เป็น มันยังคงเป็นคะแนนเท่าเดิม
KSFT
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.