假设我们要执行一组n作业,每个作业都需要单位时间。在任何时候,我们都可以提供一份工作。只有在不迟于最后期限执行作业时,i才能为我们赚取利润。
如果存在至少一个序列,使得集合中的每个任务不晚于其最后期限执行,我们就可以实现一组可行的任务。“最早期限优先”是可行的。
证明贪婪算法是最优的:在每一步中加入尚未考虑的利润值最高的作业,前提是所选的作业集仍然可行。
必须首先做到这一点:首先说明总是可以重新调度两个可行序列(一个由贪心计算),以同时调度两个序列共有的每个作业。这个新序列可能包含间隙。
更新
我创建了一个似乎推翻了算法的例子:
承担4项工作:
工作A有利润1,时间期限2,截止日期前3天;
工作B有利润4,期限1,截止日期前4天;
工作C有利润3,期限1,截止日期前3天;
工作D有利润2,时间期限1,截止日期在第2天之前。
如果我们先使用利润最高的贪婪算法,那么我们只能得到作业B&C。但是,如果我们先做最后期限,那么我们就可以得到所有的作业,并且顺序是CDB
不确定我是否以正确的方式来处理这个问题,因为我创建了一个例子来反驳这个问题想要什么

最佳答案

事实上,“最早期限优先”、“最高利润优先”和“最高利润/持续时间优先”都不是正确的算法…
承担两项工作:
工作A有利润1,时间期限1,截止日期前1天;
工作B有利润2,时间期限2,截止日期前2天;
然后“最早期限优先”没有得到正确答案。正确答案是B。
再承担5项工作:
工作A有利润2,时间期限3,截止日期前3天;
工作B有利润1,时间期限1,截止日期前1天;
工作C有利润1,时间期限1,截止日期前2天;
工作D有利润1,时间期限1,截止日期前3天;
工作E有利润1,时间期限1,截止日期在第4天之前;
然后“利润第一”得不到正确答案。正确答案是BCDE。
再承担4项工作:
工作A有利润6,期限4,截止日期前6天;
工作B有利润4,期限3,截止日期6日前;
工作C有利润4,时间期限3,截止日期前6天;
作业D的利润为0.0001,持续时间为2,截止日期为第6天之前;
然后“最高利润/持续时间优先”无法得到正确答案。正确答案是bc(感谢@dognose的反例,见注释)。
一个正确的算法是动态规划:
按截止日期升序排列的第一个订单。dp[i][j] = k意味着在第一个i工作和j时间单位内,我们可以获得k最高利润。然后开始dp[0][0] = 0
作业信息存储在3个数组中:利润存储在profit[i], 1<=i<=n中,持续时间存储在time[i], 1<=i<=n中,截止时间存储在deadline[i], 1<=i<=n中。

  // sort by deadline in ascending order
  ...
  // initially 2 dimension dp array are all -1, -1 means this condition unreachable
  ...
  dp[0][0] = 0;
  int maxDeadline = max(deadline); // max value of deadline
  for(int i=0;i<n;i++) {
      for(int j=0;j<=maxDeadline;j++) {
          // if do task i+1 satisfy deadline condition, try to update condition for "within the first i+1 jobs, cost j+time[i+1] time units, what's the highest total profit will be"
          if(dp[i][j] != -1 && j + time[i+1] <= deadline[i+1]) {
              dp[i+1][j+time[i+1]] = max(dp[i+1][j+time[i+1]], dp[i][j] + profit[i+1]);
          }
      }
  }
  // the max total profit can get is max value of 2 dimension dp array

DP算法的时间/空间复杂度(即n*mn为作业计数,m最大期限)高度依赖于多少作业和最大截止时间。如果n和/或m相当大,则可能很难得到答案,而对于一般用途,则效果很好。

08-26 08:37