Thử thách tối ưu hóa thuật toán nhanh nhất


9

Đây là thử nghiệm đầu tiên của tôi với một thách thức phức tạp tiệm cận mặc dù tôi hài lòng với các câu trả lời hoàn toàn bằng mã miễn là chúng đi kèm với lời giải thích về độ phức tạp thời gian của chúng.

Tôi có vấn đề sau đây.

Hãy xem xét các nhiệm vụ T_1, ... T_n và procs M_1, ..., M_m. Mỗi tác vụ cần một khoảng thời gian nhất định để thực hiện tùy thuộc vào procs.

Mỗi tác vụ cũng tốn một khoản tiền nhất định để thực hiện tùy thuộc vào procs.

Các nhiệm vụ phải được thực hiện theo thứ tự nghiêm ngặt (chúng không thể được thực hiện song song) và cần có thời gian để thay đổi Proc. Một nhiệm vụ không thể được chuyển từ Proc này sang Proc khác sau khi nó đã được bắt đầu.

Cuối cùng, mỗi nhiệm vụ phải được hoàn thành trong một thời gian nhất định.

nhiệm vụ

Mục tiêu là đưa ra một thuật toán (hoặc một số mã) đưa ra năm bảng của biểu mẫu ở trên, giảm thiểu tổng chi phí để hoàn thành tất cả các nhiệm vụ trong khi đảm bảo tất cả các nhiệm vụ được hoàn thành theo thời hạn. Nếu điều này là không thể, chúng tôi chỉ báo cáo rằng nó không thể được thực hiện.

ghi bàn

Bạn nên đưa ra độ phức tạp Oh lớn cho giải pháp của mình theo các biến n, m và d, trong đó d là thời hạn cuối cùng. Không nên có hằng số không cần thiết trong độ phức tạp Oh lớn của bạn. Vì vậy, O (n / 1000) nên được viết là O (n).

Điểm của bạn được tính đơn giản bằng cách đặt n = 100, m = 100 và d = 1000 vào độ phức tạp đã nêu của bạn. Bạn muốn điểm số nhỏ nhất có thể.

máy cắt cà vạt

Trong trường hợp hòa, câu trả lời đầu tiên sẽ thắng.


thêm ghi chú

log trong thời gian phức tạp của một câu trả lời sẽ được lấy cơ sở 2.

bảng điểm

  • 10 ^ 202 từ KSFT ( Python ) Lần đầu tiên được gửi để nhận tiền thưởng.
  • 10 ^ 202 từ Dominik Müller ( Scala )

"Chuyển thời gian từ máy hàng sang máy cột" Ý bạn là chi phí thời gian để chuyển từ M_1 sang M_2? Ngoài ra, sự khác biệt giữa "chi phí chuyển đổi" và "thời gian chuyển đổi". Chúng thường có nghĩa tương tự liên quan đến việc mô tả các thuật toán lập lịch.
Sáng

@Lum Hãy nghĩ về thời gian tính bằng giây và chi phí bằng đô la. Chúng là những điều khác nhau trong câu hỏi này. Các bảng hiển thị thời gian (chi phí tương ứng) của máy thay đổi để thực hiện tác vụ tiếp theo. Điều này có thể từ M_1 đến M_2 hoặc từ M_2 đến M_1.

Ok, điều đó làm rõ rằng.
Sáng

Câu trả lời ngắn gọn là sự phức tạp sẽ là O(m ^ n). Không có thuật toán sẽ "nhanh" hơn thế. Cắt tỉa dựa trên thời gian tối đa hoặc chi phí yêu cầu không làm thay đổi độ phức tạp của thuật toán, cũng như không có cả chi phí đô la và chi phí thời gian, do đó dkhông phải là một yếu tố của sự phức tạp.
Bob Dalgleish

1
@BobDalgleish Điều đó cho điểm 100 đến sức mạnh của 100. Tôi tin rằng bạn có thể làm tốt hơn rất nhiều.

Câu trả lời:


2

Điểm: 10 ^ 202

Tôi ước gì chúng tôi có hỗ trợ LaTeX ngay bây giờ ...

Vì không có ai trả lời, tôi nghĩ tôi sẽ thử, mặc dù nó không hiệu quả lắm. Tôi không chắc chắn O lớn của nó là gì, mặc dù.

Tôi nghĩ rằng nó hoạt động. Ít nhất, nó làm cho trường hợp thử nghiệm duy nhất được đăng.

Nó nhận đầu vào như trong câu hỏi, ngoại trừ không có nhãn số máy hoặc số tác vụ và với dấu chấm phẩy thay vì ngắt dòng.

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

Bạn có thể cung cấp một số lời giải thích và nói những gì bạn cảm thấy điểm của bạn nên được? Ngoài ra, bạn có thể chỉ ra những gì nó đưa ra cho ví dụ trong câu hỏi không?

Như tôi đã nói trong câu trả lời của mình, tôi đã thử nó và nó hoạt động trên ví dụ. Tôi không chắc chữ O lớn là gì (mà tôi muốn nói trong câu trả lời của tôi).
KSFT

Về cơ bản, đại khái sẽ mất bao nhiêu thao tác để hoàn thành. Có vẻ như phải mất khoảng thời gian * m thời gian (giả sử tất cả các bài tập trong các vòng lặp mất thời gian liên tục) khiến tôi nghi ngờ về tính đúng đắn của nó, tôi phải thừa nhận. Bạn có thể nói điều gì đó về lý do tại sao bạn nghĩ rằng nó hoạt động?

1
Oh! Tôi bỏ lỡ điều đó. Vì vậy, m trong thực tế là kích thước bước sóng ^ nt Nhiệm vụ. OK bây giờ tôi tin rằng nó hoạt động. Tôi nghĩ điểm của bạn là (100 ^ 100) * 100.

4
@Lembik Nó có điểm số tốt nhất cho đến nay!
KSFT

1

Kiểm tra tất cả - Scala

Điểm ước tính: 2m ^ n

Tôi bắt đầu từ mỗi máy và lặp lại tất cả các nhiệm vụ để tạo ra tất cả các hoán vị thông qua các tác vụ với các máy khác nhau đáp ứng thời hạn. Có nghĩa là nếu mọi thứ đúng lúc tôi sẽ nhận được 9 đường dẫn có thể với 2 máy và 3 nhiệm vụ. (m ^ n) Sau đó, tôi đi theo con đường với chi phí thấp nhất.

Đầu vào được cấu trúc như thế này (-> giải thích các phần và do đó không nên nhập):

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

Và đây là mã:

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)
    }
}

Tôi cũng có một ý tưởng để bắt đầu từ phía sau. Vì bạn luôn có thể chọn một máy có chi phí thấp nhất nếu thời gian nhỏ hơn nên chênh lệch từ thời hạn trước đó đến máy mới. Nhưng điều đó sẽ không làm giảm thời gian chạy tối đa nếu tác vụ với chi phí tốt hơn mất nhiều thời gian hơn thì thời hạn cuối cùng được tính.

Cập nhật

======

Đây là một thiết lập khác. thời gian:

M_1 2 2 2 7
M_2 1 8 5 10

Giá cả:

M_1 4 4 4 4
M_2 1 1 1 1

thời gian chuyển đổi:

    M_1 M_2
M_1  0   2
M_2  6   0

chi phí chuyển đổi:

    M_1 M_2
M_1  0   2
M_2  2   0

thời hạn

5 10 15 20

Khi nhập vào chương trình của tôi:

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

Giải pháp này có hai giải pháp: thời gian: 18, chi phí: 15, đường dẫn: Danh sách (M_1, M_1, M_1, M_2) thời gian: 18, chi phí: 15, đường dẫn: Danh sách (M_2, M_1, M_1, M_1)

Điều này đặt ra câu hỏi làm thế nào điều này nên được xử lý. Tất cả nên được in hoặc chỉ một? Và nếu thời gian sẽ khác thì sao? Là một trong những chi phí thấp nhất và không có thời hạn bỏ lỡ đủ hay nó cũng nên là một trong những thời gian thấp nhất?


Câu hỏi nói rằng mục tiêu là "[giảm thiểu] tổng chi phí". Nhân tiện, bạn có thể tóm tắt cách thức thuật toán của bạn hoạt động không? Tôi không biết Scala và tôi không thể hiểu nó hoạt động như thế nào.
KSFT

Lặp lại tất cả các con đường cần có O(m^n)thời gian. Lặp lại trên mỗi máy cho tất cả các nhiệm vụ mất O(n*m^n)thời gian.
KSFT

Không O(n*m^n)lặp lại qua từng nhiệm vụ cho từng đường dẫn phải không? Và lặp lại qua từng máy cho từng nhiệm vụ một cái gì đó như thế nào O(n*m).
Dominik Müller

À, lỗi đánh máy. Tôi có nghĩa là để viết "iterating trên mỗi máy cho tất cả các con đường mất O(n*m^n)".
KSFT

Đợi đã, không, nó O(m*m^n)=O(m^n+1). Mặc dù vậy, nó vẫn là cùng một số điểm.
KSFT
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.