贪心算法——区间调度

问题描述

任务 j j j开始时间为 s j s_j sj,终止时间为 f j f_j fj,任务 j j j所在时间段即为 [ s j , f j ] [s_j,f_j] [sj,fj]。若两个任务所在时间段不重叠,则称两个任务兼容。求最大互不兼容的任务子集。

错误的贪心策略

①按照开始时间从早到晚排序,若该任务与之前任务都兼容,则选取该任务,若不兼容则不选取该任务并查看下一个任务,知道所有任务都被检查一遍结束。反例如下:
在这里插入图片描述
上述策略得到最大子集大小为1,实际最大子集大小为4

②按照时间间隔从小到大排序,若该任务与之前任务都兼容,则选取该任务,若不兼容则不选取该任务并查看下一个任务,知道所有任务都被检查一遍结束。反例如下:
在这里插入图片描述
上述策略得到最大子集大小为1,实际最大子集大小为2

③按照与自身冲突的任务数量由小到大进行排序,若该任务与之前任务都兼容,则选取该任务,若不兼容则不选取该任务并查看下一个任务,知道所有任务都被检查一遍结束。反例如下:
在这里插入图片描述
与6号块冲突的块数量为2,与1、4号块冲突的块个数为3,其余块的冲突个数为4。上述策略得到最大子集大小为3(1、6、4),实际最大子集大小为4(1、2、3、4)

正确的贪心策略(时间复杂度为 n l o g n nlogn nlogn,瓶颈为排序部分)

按照结束时间由早到晚排序,或者按照开始时间由晚到早排序,若该任务与之前任务都兼容,则选取该任务,若不兼容则不选取该任务并查看下一个任务,知道所有任务都被检查一遍结束。
我们对结束时间由早到晚排序为贪心策略进行证明
反证法:
我们假设按照以上贪心策略得到的不是最优解,且令 i 1 , i 2 , … , i k i_1,i_2,\dots,i_k i1,i2,,ik表示由贪心策略选出的任务;令 j 1 , j 2 , … , j m j_1,j_2,\dots,j_m j1,j2,,jm表示最优解中的任务,我们不妨设最优解中最多存在r个任务与贪心解中的任务相同,即 i 1 = j 1 , i 2 = j 2 , … , i r = j r i_1= j_1,i_2= j_2,\dots,i_r= j_r i1=j1,i2=j2,,ir=jr,得到结果如下图所示:
在这里插入图片描述
其中由于贪心策略,任务 i r + 1 i_{r+1} ir+1的结束时间早于任务 j r + 1 j_{r+1} jr+1,并且由于最优解中任务数一定大于贪心解任务数( m > k m>k m>k),所以任务 j r + 1 j_{r+1} jr+1一定存在。此时我们可以在不改变最优解性质的情况下,用任务 i r + 1 i_{r+1} ir+1替换任务 j r + 1 j_{r+1} jr+1,如下图:
在这里插入图片描述
此时最优解中存在r+1个任务与贪心解中的任务一致,与我们之前假设的最多存在r个任务与贪心解中的任务相同矛盾,连续推证可得,贪心解与最优解中所有任务相同,即贪心解为最优解,以上贪心策略得到的解是最优解。

以上贪心策略在给每个任务分配正权重后,求最大权重子任务集合时将不再适用。因为我们可以构造一个反例:分配给与最早结束任务不兼容任务尽可能大的权重,来打破该贪心策略

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用C++实现贪心算法解决区间调度问题的示例代码: ```cpp #include <iostream> #include <vector> #include <algorithm> // 区间结构体 struct Interval { int start; int end; }; // 比较函数,根据结束时间排序 bool compareIntervals(Interval a, Interval b) { return a.end < b.end; } // 贪心算法解决区间调度问题 int intervalScheduling(std::vector<Interval>& intervals) { // 按照结束时间排序 std::sort(intervals.begin(), intervals.end(), compareIntervals); int count = 1; // 最少需要一个区间 int endTime = intervals[0].end; // 遍历区间,选择结束时间最早的不冲突区间 for (int i = 1; i < intervals.size(); i++) { if (intervals[i].start >= endTime) { count++; endTime = intervals[i].end; } } return count; } int main() { std::vector<Interval> intervals = {{1, 3}, {2, 4}, {3, 6}, {5, 7}, {6, 8}}; int result = intervalScheduling(intervals); std::cout << "最多可安排的任务数量: " << result << std::endl; return 0; } ``` 在这个示例中,我们定义了一个`Interval`结构体来表示区间,并实现了一个比较函数`compareIntervals`,用于根据结束时间对区间进行排序。`intervalScheduling`函数使用贪心算法解决区间调度问题,首先对区间按照结束时间进行排序,然后从第一个区间开始遍历,选择结束时间最早的不冲突区间,并计数。最后输出最多可安排的任务数量。 在主函数中,我们创建了一个包含几个区间的示例输入,然后调用`intervalScheduling`函数计算结果,并输出最多可安排的任务数量。 注意:这只是一个简单的示例,实际问题可能需要根据具体情况进行更复杂的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值