关于贪心算法之活动安排问题的理解

问题一:有若干个活动,第i个开始时间和结束时间是[Si,fi),只有一个教室,活动之间不能交叠,求最多安排多少个活动?
求一个教室能安排几个活动,那么就是说用一个教室去选择最多的活动,那么最优的方法肯定就是选择的活动都能不重叠的按次序开始,也就是说每个活动的结束那么恰好在最短的等待时间内有一个活动开始,但如何选择?
能否按照开始时间进行选择,先选择开始时间最早的一个活动,结束后选择等待时间开始最早的一个活动,答案是否定的,可以用一个例子说明。
[0, 100), [1,2) ,[2, 3), [3, 4),[4,5],安排[0,100)的这个活动之后,其他活动无法安排,可是最优解是安排除它外的4个活动。
那要么按照活动进行最短的策略进行安排,这样就可以避免第一种情况那样开始时间最早的活动占用的时间最长的问题,答案也是否定的。
[0,5) [5,10) [3, 7), 这里[3,7)最短,但如果我们安排了[3,7),其它两个无法安排了。但是最优解显然是安排其它两个,而放弃[3,7),可见这个贪心策略也是不行的。
既然上面安排活动是想减少冲突,那么如果我们优先安排冲突最少的活动可以么?至少从(1)和(2)看来,这个策略是有效的。真是对的么? 尝试这个例子
[0,2) [2,4) [4,6) [6,8)
[1,3) [1,3) [1,3) [3,5) [5,7) [5,7) [5,7
[2,4)和4个活动冲突3个[1,3)和一个[3,5)
[4,6)和也和4个活动冲突3个[5,7)和一个[3,5)
[6,8)和3个活动冲突——3个[5,7)

下面[1,3)和[5,7)每个都和5个活动冲突,
而[3,5)只和两个活动冲突——[2,4)和[4,6)。那按照我们的策略应该先安排[3,5), 可是一旦选择了[3,5),我们最多只可能安排3个活动。
但明显第一行的4个活动都可以安排下来,所以这种策略也是不对的。
最后只能考虑按照结束时间最早安排活动了,这种解决策略是对的,为什么呢?
安排最多活动本质不就是安排一串不连续但间隔最小的线段,如果选择结束时间最早的一个活动,紧接着开始时间离上一个活动结束时间最近的一个活动,那么可以解决以上策略的各种冲突

#include<iostream>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
struct action
{
	int b;
	int e;
};
bool compare(const action &a,const action &b)
{
	if (a.e < b.e) return true;
	else return false;
}
int main()
{
	int n;
	cin >> n;
	action *a = new action[n + 1];
	int minn = inf;
	for (int i =1; i <= n; i++)
	{
		cin >> a[i].b >> a[i].e;
	}
	//cout << minn << endl;
	sort(a+1, a + n + 1, compare);
	/*for (int i = 1; i <= n; i++)
	{
		cout << a[i].b<<"    "<< a[i].e<<endl;
	}
	*/
	
	int count = 1,j=a[1].e;
	for (int i = 2; i <= n; i++)
	{
		if (a[i].b  >= j)
		{
			count++;
			j = a[i].e;
		}
	}
	cout << count << endl;
	getchar();
	getchar();
	

}

问题二
有若干个活动,第i个开始时间和结束时间是[Si,fi),活动之间不能交叠,要把活动都安排完,至少需要几个教室?

现在又换成活动选教室了,那么我们把开始时间和结束时间进行排序,遇到开始时间就加一(需要增加一个教室),遇到结束时间减一(活动结束空出一个教室),如果开始时间等于结束时间就往下继续(那么下一个活动就紧接着在这个教室进行,不需要增加或减少教室)。

#include<iostream>
#include<algorithm>
using namespace std;
int a[10010], b[10010];
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i] >> b[i];
	sort(a, a + n);
	sort(b, b + n);
	int i = 0, j = 0, count = 0, minn = 0;
	while (i < n&&j < n)
	{
		if (a[i] < b[j])
		{
			count++;
			i++;
		}
		else if (a[i] > b[j])
		{
			count--;
			j++;
		}
		else if (a[i] == b[j])
		{
			i++;
			j++;
		}
		minn = max(minn, count);
	}
	cout << minn << endl;
	getchar();
	getchar();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值