线性复杂度的调度算法

时间:2015-04-19 04:53:00

标签: algorithm time-complexity

问题在于:

我们有n天完成任务。我们每天可以完成一项任务。每个任务都有一个开始日期和结束日期。我们无法在开始日期之前开始任务,必须在结束日期之前完成。因此,给定开始日期的向量s和结束日期的e给出向量d,如果存在,则d[i]是您执行任务的日期{ {1}}。例如:

i

我们有一个可能的解决方案:

s = {1, 0, 1, 2, 0}
e = {2, 4, 2, 3, 1}

+--------+------------+----------+
| Task # | Start Date | End Date |
+--------+------------+----------+
|      0 |          1 |        2 |
|      1 |          0 |        4 |
|      2 |          1 |        2 |
|      3 |          2 |        3 |
|      4 |          0 |        1 |
+--------+------------+----------+

使用O(n ^ 2)创建算法是微不足道的。使用O(nlogn)创建算法也不算太糟糕。据推测,算法可以给出O(n)的解。那会是什么?

3 个答案:

答案 0 :(得分:1)

当你不能使用时间时,请使用空间!您可以使用位向量表示任何一天打开的任务。在O(n)中创建一个“今天开始”数组。您还可以使用另一个也可以在O(n)中计算的位向量来表示最快结束的任务。然后最后,在O(n)中每天再次扫描,从那天开始添加任何任务,选择那天开放的最低编号的任务,优先考虑最快结束的任务。

using System.IO;
using System;
using System.Math;

class Program
{
    static void Main()
    {
        int n = 5;

        var s = new int[]{1, 0, 1, 2, 0};
        var e = new int[]{2, 4, 2, 3, 1};

        var sd = new int[n];
        var ed = new int[n];
        for (int task = 0; task < n; task++)
        {
            sd[s[task]] += (1 << task);  // Start for task i
            ed[e[task]] += (1 << task);  // End for task i
        }

        int bits = 0;

        // Track the earliest ending task
        var ends = new int[n];
        for (int day = n-1; day >= 0; day--)
        {
            if (ed[day] != 0)           // task(s) ending today
            {
                // replace any tasks that have later end dates
                bits = ed[day];
            }
            ends[day] = bits;
            bits = bits ^ sd[day];       // remove any starting
        }

        var d = new int[n];
        bits = 0;
        for (int day = 0; day < n; day++)
        {
            bits |= sd[day];              // add any starting

            int lowestBit;

            if ((ends[day] != 0) && ((bits & ends[day]) != 0))
            {
                // Have early ending tasks to deal with
                // and have not dealt with it yet
                int tb = bits & ends[day];
                lowestBit = tb & (-tb);
                if (lowestBit == 0) throw new Exception("Fail");
            }
            else
            {
                lowestBit = bits & (-bits);
            }
            int task = (int)Math.Log(lowestBit, 2);

            d[task] = day;
            bits = bits - lowestBit;      // remove task
        }

        Console.WriteLine(string.Join(", ", d));
    }
}

在这种情况下的结果是:正如预期的那样,1,4,2,3,0。

答案 1 :(得分:0)

如果我错了,请纠正我,但我相信这些问题的名称将是 Interval Scheduling。

在您的帖子中,我假设您没有寻找最佳时间表,并且您只是想在O(n)中寻找任何解决方案。

这里的问题是排序将采用O(nlogn)并且计算也将采用O(nlogn)。您可以尝试一步完成:

定义V - &#39;时间的矢量&#39;为每项任务。

定义P - 在给定任务之前完成的任务向量。 即如果任务2在任务3之前完成,则[3] = 2。

当然,正如您所看到的,主要计算涉及找到P [j]。您始终采用最新结束的非重叠任务。

因此,找到P [i]。找到在第i个任务之前结束的任务。如果存在多个,请选择最后结束的那个。

定义M - 包含结果槽的向量。

算法:     WIS(n)的

M[0] <- 0
for j <- 1 to n
    do M[j] = max(wj + M[p(j)], M[j-1])
return M[n]

答案 2 :(得分:-1)

按结束日期,开始日期排序。然后按排序顺序处理数据,仅执行开始日期之后的任务。