(一本通_高手训练)游戏通关
游戏通关
【题目描述】
XY在玩一个包含N个任务的游戏。每个任务完成时限为Ti(你可以认为还没开始做任务时的时间为0),奖励为Wi。由于XY技术的娴熟以及任务的简单,对于每个任务,他都可以在一个单位时间内完成。
XY想要知道他能够获得的最多的奖励。
【输入】
第一行一个整数N,表示需要完成的任务数目。
接下来N行,每行两个整数T、W,分别表示完成这个任务的最后期限和完成这个任务后获得的奖励。
【输出】
输出数据有且仅有一行,只包含一个整数,表示最多获得的奖励。
【输入样例】
2 1 5 1 4
【输出样例】
5
【样例输入2】
5 2 3 1 2 4 5 1 3 3 4
【样例输出2】
15
【样例解释2】
对于样例2,XY可以选择完成任务1、3、4和5,这样他可以获得奖励15。
【数据规模及约定】
对于10%的数据,N≤100,Ti≤100,Wi≤2000。
对于30%的数据,N≤1000,Ti≤5000,Wi≤2000。
对于50%的数据,N≤10000,Ti≤20000,Wi≤2000。
对于100%的数据,N≤200000,Ti≤200000,Wi≤2000。
思路:
这道题解法即为贪心+大根堆,首先我们观察,对于从第二晚结束的任务的结束的时间t2+1开始到结束时间最大的任务的结束时间t1结束,这段时间内只能做最晚结束的任务;对于从第三晚的任务的结束时间t3+1开始,到第二晚的任务的结束时间内,只能做第二晚或者最晚的任务········,因此以此类推对于某一时刻,值可以做结束时间大于此时刻的任务,于是就有一种贪心策略,即每次选取可行的任务中的利益最大的任务。我们开始将数据存在结构体中,并对结构体按照时间从大到小排序。然后我们倒叙枚举时刻,用大根堆维护,使用一个变量tot记录已经加入过堆中元素的个数,每枚举到一个时刻,扫描tot至n,如果此任务的结束时间大于或等于我们枚举到的时刻就将其加入堆中,注意:我们枚举的时刻是结束时间因而从所有任务的结束时刻的最大值枚举到最晚的结束时刻1。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define maxn 200010 9 #define M(x,y) make_pair(x,y) 10 #define clear(a) memset(a,0,sizeof a) 11 12 int n,tim,tot,ans; 13 struct edge{ 14 int t,v; 15 }e[maxn]; 16 priority_queue<int>Q; 17 18 bool cmp(edge a,edge b) 19 { 20 return a.t>b.t; 21 } 22 23 int main() 24 { 25 freopen("game.in","r",stdin); 26 freopen("game.out","w",stdout); 27 scanf("%d",&n); 28 for(int i=1;i<=n;i++) 29 { 30 scanf("%d%d",&e[i].t,&e[i].v); 31 tim=max(tim,e[i].t); 32 } 33 sort(e+1,e+n+1,cmp); 34 for(int i=tim;i>=1;i--) 35 { 36 while(e[tot+1].t>=i)Q.push(e[++tot].v); 37 if(!Q.empty()) 38 { 39 ans+=Q.top(); 40 Q.pop(); 41 } 42 } 43 cout<<ans<<"\n"; 44 return 0; 45 }