校园活动 | ||
Accepted : 18 | Submit : 73 | |
Time Limit : 1000 MS | Memory Limit : 65536 KB |
Description 校园文化节的时候,Bob被好友推荐到学校当志愿者。学校一共有n个活动,每个活动有一个开始时间s和一个结束时间t(包括时间s和时间t)。每个活动开始时,这个活动的负责人就会去找空闲的志愿者帮忙。因为Bob特别有能力,活动负责人都会优先喊他去帮忙。也就是说,只要Bob有空,就会被人叫去帮忙。当然,同一时间,Bob只能去一个活动帮忙。而活动负责人在活动开始以后会非常忙而不会注意是否有人离开。所以只要过了开始时间Bob可以随时离开这个活动。然而熟悉一个新活动所需要花费的代价很大,所以Bob宁愿一直呆在一个已经熟悉了的活动也不愿更换动。Bob是个非常聪明的人,所以他可能会中途退出某个活动参加另一个活动来避开更多的活动。 Input 第一行为一个正整数,表示样例的数目。对于每一个测试样例的第一行为一个正整数n(0<n<100000),表示活动的数目,接下来的n行中的第i(1<=i<=n)行由两个正整数Si、Ti(0<S<=T<1000000)组成,分别表示第i个活动的开始时间和结束时间。 Output 对于每一个测试样例,输出Bob最少需要参加的活动数。 Sample Input 4 1 1 10 2 5 7 1 5 2 1 5 6 7 4 1 15 9 25 6 17 20 30 Sample Output 1 1 2 2 Hint 对于第二个样例,Bob被叫去活动2,完成活动2后,时间点为5,没有符合条件的活动了。 对于第四个样例,Bob先去活动1;最后他可以在中途出来去活动2,或者等活动1完成以后,去活动4。这样只需要去2个活动。 |
题意: 给你n个活动区间,可能一个活动区间还没结束另一个活动就开始了,策略就是你可以选择跳或者不跳,从而使自己尽量少的参加活动。
这个题是模拟赛的时候碰到的题,当时和hz讨论了很久,但由于当时思路不清晰没能A,后来仔细想了一下举了一些特例,找出来最佳贪心策略,然后果断AC。
思路:具体贪心策略,对于每个活动,有两种选择一个是跳出这个活动和不跳出这个活动,不管如何选择count总会加一,那么就要看跳出好,还是不跳等这个活动结束然后进入下一个活动好,那么我们不管具体是多少,就选择他们之中结束时间晚的。那么这样就可以从局部最优解推出整体最优解了。
同时,还要注意结束边界的控制,如果一个活动的包括了最后一个活动的话,那么两种情况都不用选了直接等它结束就可以了。
特例:1—5 2—8 6—10 9—11 这个情况下肯定选择2-8和6-10中结束时间晚的那个
Code:
#include <stdio.h>
#include <algorithm>
using namespace std;
struct node{
int s,e;
}a[100000];
bool cmp(node a,node b) //按开始时间小到大,结束时间大到小排序
{
if(a.s<b.s)
return true;
else if(a.s==b.s&&a.e>b.e)
return true;
return false;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
int i,edge,max,j,count=1;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&a[i].s,&a[i].e);
sort(a,a+n,cmp);
edge=a[n-1].s; //边间设为开始时间最晚的那个
max=0;
for(i=0;i<n;)
{
int k;
if(a[i].e>=edge) //如果当前进入的活动结束时间包括了edge那么久这个活动结束就行了
break;
else
{
for(j=i+1;i<n;j++) //否则开始找这个活动包括的活动中能到达最晚的时候
{
if(a[j].s>a[i].e)
break;
if(a[j].e>max)
{
max=a[j].e;
k=j;
}
}
if(a[j].e>max) //和这个活动不包括的下一个活动相比选最晚的那个
{
max=a[j].e;
k=j;
}
}
i=k; //然后进入那个活动,继续循环
count++;
}
printf("%d\n",count);
}
return 0;
}
贪心问题,一定要思路清晰,找特殊案例很重要啊。