题目:http://acm.hdu.edu.cn/showproblem.php?pid=4415
题意:一个专家级的杀手,他有一个m耐久度的武器和n个敌人,杀死一个敌人需要消耗ai点的耐久,但是可以获得他的武器,用他的武器可以杀死bi个其他敌人,问这个杀手最多可以杀死多少敌人,在杀人最多的情况下最小消耗的耐久度为多少。
题解:贪心题,把敌人按bi的值分为零(a集合)和非零(b集合)两个集合。
情况一:先考虑a集合,对于这个集合,我们只要杀死其中一个,就可以通过获取敌人的武器在不消耗更多的耐久的情况下消灭这个集合的所有人。因此我们选择用自己的武器杀死这个集合中消耗耐久最少的敌人且获取了这个集合中所有的武器。接着,我们可以把b集合按ai值从小到大排序,然后用从a集合中获取的武器杀死ai代价较大的敌人。如果这个时候敌人消灭完了,就输出。如果还有剩余的敌人,我们把a集合中之前是用敌人的武器杀死的和b集合中剩下的敌人放在一起考察,此时有两种情况:1)用自己的武器杀掉a集合中原来用敌人武器杀掉的中ai代价最小的,同时可以用这个原来杀他的敌人武器杀掉b集合中剩下的ai代价的最大的。2)用自己的武器杀掉b为0中a最小的。
情况二:先考虑b集合,把b集合的敌人处理完,如果还有多余的耐久度再处理a集合的敌人。
最后答案是两种情况的结合。
测试数据:
4
3 5
4 1
5 1
7 7
2 1
2 2
4 0
5 2
1 2
1 1
5 0
5 0
5 0
5 7
3 2
4 1
5 0
6 0
7 0
Case 1:3 4
Case 2:0 0
Case 3:5 2
Case 4:5 7
代码:
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; struct px { int a,b; } node; vector<struct px> a,b; bool cmp(const struct px &x,const struct px &y) { return x.a<y.a; } int main() { int tt; int x,y,n,m,ida,idb; scanf("%d",&tt); for(int cas=1; cas<=tt; ++cas) { int ans=0,bx=0,mm=0,mn=0,ansn=0; a.clear(); b.clear(); scanf("%d%d",&n,&m); for(int i=0; i<n; i++) { scanf("%d%d",&node.a,&node.b); if(node.b!=0) a.push_back(node); else b.push_back(node); } sort(a.begin(),a.end(),cmp); sort(b.begin(),b.end(),cmp); ida=0; idb=b.size()-1; for(int i=0; i<b.size(); ++i) { if(m-mn>=b[i].a) { ansn++; mn+=b[i].a; } } if(a.size()>0&&a[0].a<=m) { node=a[0]; mm+=node.a; for(int i=0; i<a.size(); i++) { bx+=(a[i].b-1); ans++; } bx++; } if(a.size()>0&&a[0].a<=m-mn) { node=a[0]; mn+=node.a; for(int i=0; i<a.size(); i++) ansn++; } for(; bx!=0&&idb>=0; --idb,--bx,++ans); if(idb<0) { if(ans>ansn) printf("Case %d: %d %d\n",cas,ans,mm); else if(ans<ansn) printf("Case %d: %d %d\n",cas,ansn,mn); else printf("Case %d: %d %d\n",cas,ansn,mn>mm?mm:mn); } else { int i,j; for(i=1,j=0; i<a.size()&&j<=idb;) { if(a[i].a<=b[j].a) { if(m>=a[i].a+mm) { mm+=a[i].a; i++; ans++; idb--; } else break; } else { if(m>=b[j].a+mm) { mm+=b[j].a; ans++; j++; } else break; } } for(;j<=idb;++j) { if(m>=b[j].a+mm) { mm+=b[j].a; ans++; j++; } else break; } if(ans>ansn) printf("Case %d: %d %d\n",cas,ans,mm); else if(ans<ansn) printf("Case %d: %d %d\n",cas,ansn,mn); else printf("Case %d: %d %d\n",cas,ansn,mn>mm?mm:mn); } } return 0; }