nkoj 1349
Description
Farmer John 有太多的工作要做啊!!!!!!!!为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间。
他的工作日从0时刻开始,有1000000000个单位时间(!)。在任一时刻,他都可以选择编号1~N的N(1 <= N <= 100000)项工作中的任意一项工作来完成。
因为他在每个单位时间里只能做一个工作,而每项工作又有一个截止日期,所以他很难有时间完成所有N个工作,虽然还是有可能。
对于第i个工作,有一个截止时间D_i(1 <= D_i <= 1000000000),如果他可以完成这个工作,那么他可以获利P_i( 1<=P_i<=1000000000 ).
在给定的工作利润和截止时间下,FJ能够获得的利润最大为多少呢?答案可能会超过32位整型。
Input
第1行:一个整数N.
第2~N+1行:第i+1行有两个用空格分开的整数:D_i和P_i.
Output
输出一行,里面有一个整数,表示最大获利值。
Sample Input
3
2 10
1 5
1 7
Sample Output
17
分析:
贪心+堆
1.将罐头按到期时间有小到大排序
2.依次讨论每个罐头:
若当前讨论i号罐头,它的到期时间为date_i,此时,我们最多能选date_i个罐头出来。
所以,我们分两种情况讨论:
<1>若在i之前选的罐头数小于Time_i,我们直接选择i号罐头
<2>若在i之前已选的罐头数>=TIme_i,那么把我们在已选罐头中美味值最小的一个拿来与i号罐头比较,
若i号罐头的美味值大于该罐头,则将该罐头从已选罐头列表中删除,把i号罐头加入到里面。
否则,不选用i号罐头
3.我们要从一堆已选的罐头中快速选出美味值最小者,显然用小根堆来维护已选出的罐头即可。
另外,注意数据范围是10^9,要使用long long
一点感受:
做这道题的时候首先想到的是动态规划,也想到了堆+贪心,但是却没有细想。所以赛场上不怕有多种思路,不妨列出来,一种一种尝试即可。切不可犹豫不决,对每种方法仔细思考,不能凭主观感受,浅尝辄止。例如本题中,想先到动规是没有错误的,但是仔细研究后会发现,状态有后效性,无法由前面的状态转移的得出。这种时候就应该果断放弃这种思路。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
const int maxn=100000+5;
int n;
struct Work{
LL date,w;
bool operator < (const Work a)const {
return date<a.date;
}
}s[maxn];
priority_queue< LL,vector<LL>,greater<LL> > q; //小根堆
int main(){
int i;
scanf("%d",&n);
LL ans=0;
for(i=1;i<=n;i++)
scanf("%I64d%I64d",&s[i].date,&s[i].w);
sort(s+1,s+1+n);
for(i=1;i<=n;i++){
if(q.size()<s[i].date)q.push(s[i].w); //没有选出date_i个
else if(q.top()<s[i].w){ // 比之前选出的最小的更优
q.pop();
q.push(s[i].w);
}
}
while(!q.empty())ans+=q.top(),q.pop();
printf("%I64d",ans);
}