贪心算法(区间调度问题)

问题描述:

有n项工作,每项工作分别在si开始,ti结束。对每项工作,你都可以选择参加或不参加,但选择了参加某项工作就必须至始至终参加全程参与,即参与工作的时间段不能有重叠(即使开始的时间和结束的时间重叠都不行)。

如何尽可能多的参加工作呢?

限制条件:

1<=n<=100000

1<=si<=ti,=109

样例:

输入

n=5

s={1,2,4,6,8}

T={3,5,7,9,10}
5
1 2 4 6 8
3 5 7 9 10

 

输出

3(选择工作1, 3, 5)

思路:

在可选的工作中,每次都选取结束时间最早的工作,消去重叠的

有一个直观但不是很准确的思路,结束时间越早后面可以工作的工作就越多

源代码

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100;
int ans=0;
pair<int, int> p[maxn];
//有n项工作,每项工作分别在si开始,ti结束。对每项工作,你都可以选择参加或不参加,但选择了参加某项工作就必须至始至终参加全程参与,即
//参与工作的时间段不能有重叠(即使开始的时间和结束的时间重叠都不行)。
/*
5
1 2 4 6 8
3 5 7 9 10
*/
int main() {
	int n, S[maxn], T[maxn];
	cin >> n;
	for (int i=0; i<n; i++) {
		cin >> S[i];
	}
	for (int i=0; i<n; i++) {
		cin >> T[i];
	}
	for (int i=0; i<n; i++) {
		p[i].first = T[i];//结束 
		p[i].second = S[i];//开始 
	}

	sort(p,p+n);//排序,使最快结束的工作排到前面 
	int t=0;
	for (int i=0; i<n; i++) {
		if (t<p[i].second) {//结束的时候应该在下一个开始的前面,否则重叠 
			ans++;
			t=p[i].first;//当前所在秒数更新 
		}
	}
	
	cout << ans << endl;
	
	return 0;
}

 

好的,贪心算法是一种常用的算法思想,它通常用于解决最优化问题。反证法是一种证明方法,它通过假设所要证明的命题不成立,然后推导出矛盾,从而证明该命题成立。 在间隔调度问题中,我们需要从一组任务中选择一些任务进行调度,每个任务有一个开始时间和结束时间。我们的目标是选择尽可能多的任务,使得它们之间没有重叠的时间段。 贪心算法可以用来解决这个问题。具体来说,我们可以按照任务的结束时间从小到大排序,然后依次选择结束时间最早的任务,并且保证所选任务与前面已选任务不重叠。这样做的正确性可以通过反证法证明。 假设我们按照上述方法得到了一个调度方案,但是这个方案不是最优的。那么一定存在一个最优方案,其中有一个任务与我们的方案不同。假设这个任务是最优方案中结束时间最早的任务。 由于我们的方案是按照结束时间从小到大排序得到的,所以这个任务的结束时间一定不晚于我们方案中最后一个任务的结束时间。因此,这个任务与我们方案中最后一个任务不重叠。 现在我们将最后一个任务替换成这个任务,得到一个新的方案。由于这个任务是最优方案中结束时间最早的任务,所以这个新方案一定不劣于原方案。但是这个新方案比原方案多选择了一个任务,因此它一定更优。这与我们的假设矛盾,因此假设不成立,我们的方案是最优的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值