假设我们要执行一组n
个作业,每个作业需要一个单位时间。在任何时候我们都可以完成一项工作。作业i
,1<=i<=n
只有在截止日期之前执行,才能为我们赢利。
如果至少有一个序列允许在不超过截止日期的时间内执行集合中的每个作业,那么我们可以完成一组作业。 &#34;最早的截止日期&#34;是可行的。
显示贪婪算法是最优的:如果所选择的一组作业仍然可行,则在每个步骤中添加尚未考虑的具有最高利润值的作业。
必须首先执行:首先显示始终可以重新安排两个可行序列(一个由Greedy计算),以便同时安排两个序列共有的每个作业。这个新序列可能包含间隙。
更新
我创建了一个似乎反驳算法的例子:
假设有4个职位:
如果我们首先使用最高利润的贪婪算法,那么我们只得到工作B&amp; C.但是,如果我们先做截止日期,那么我们可以获得所有工作,而且订单是CDB
不确定我是否以正确的方式接近这个问题,因为我创建了一个例子来反驳问题所需要的
答案 0 :(得分:1)
事实上,最早的截止日期不是第一个&#34;,&#34;最高的利润第一&#34;也不是&#34;最高的利润/持续时间&#34;是正确的算法...
假设2个职位:
然后&#34;最早的截止日期&#34;未能得到正确的答案。正确答案是B。
假设另外5个工作:
然后&#34;最高利润第一&#34;未能得到正确的答案。正确答案是BCDE。
假设另外4个工作:
然后&#34;最高利润/持续时间第一&#34;未能得到正确的答案。正确答案是BC(感谢@ dognose&#39的反例,见评论)。
一种正确的算法是动态编程:
按截止日期递增的第一个订单。 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*m
,n
是作业计数,m
是最大期限)高度依赖于作业数量和最大期限。如果n
和/或m
相当大,可能很难得到答案,而对于常见用途,它会很好用。
答案 1 :(得分:0)
此问题看起来像作业车间调度,这是NP完全的(这意味着没有最佳的贪婪算法 - 尽管专家们试图找到一个自70&#39; S)。 Here's a video在该用例的更高级形式上,使用Greedy算法然后进行本地搜索来解决。
如果我们假设您的用例确实可以放宽到Job Shop Scheduling,那么有许多优化算法可以提供帮助,例如Metaheuristics(包括禁忌搜索和模拟退火等本地搜索),(M)IP,动态编程,约束编程,...有这么多选择的原因是因为没有一个是完美的。我更喜欢Metaheuristics,因为他们在我所见过的所有研究挑战中超出了其他人。
答案 2 :(得分:0)
这个问题称为有期限的作业排序,可以通过两种基于贪婪策略的算法来解决: