HDU 4415 Assassin’s Creed
题意: 一个人有一把剑,剑有一个耐久度m,现在有n个敌人,每个敌人都对应一个ai值和bi值,ai表示
杀掉这个敌人需要消耗ai的的武器耐久度,同时可以获得他的剑并且可以用他的剑杀死bi个敌人,
问最多可以杀掉多少个敌人。
分析: 有两种情况:
①只杀 bi为 0 的;
②杀了某个bi不为 0 的敌人,那么所有bi不为 0 的最后都会被杀掉,
这种情况只要枚举多少个bi不为0 的敌人是花自己的耐久度去杀的,找一个最优解
要让用耐久度杀的敌人消耗的耐久度尽可能小,需要实现按照ai排序,找ai最小的每次。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 #define INF 0x1f1f1f1f struct node { int ai,bi; }vb[maxn],vnob[maxn],tmp; // bi不为0的集合,bi为0的集合 bool cmp(node a,node b) { return a.ai<b.ai; } int main() { int t,n,i,j,ca=1,m; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); int sumb=0; int vb_top=0,nob_top=0; for(i=1;i<=n;i++) { scanf("%d%d",&tmp.ai,&tmp.bi); if(tmp.bi) { sumb+=tmp.bi; // 统计可以获得的敌人的武器数 vb[vb_top++]=tmp; // bi 不为 0 的 } else vnob[nob_top++]=tmp; // bi 为 0 的 } sort(vb,vb+vb_top,cmp); sort(vnob,vnob+nob_top,cmp); int ansn=0,ansd=0,sum=0; int ta=0,td=0,fr=0; int tm=m; for(i=0;i<nob_top;i++) // 只杀bi为0的集合的情况 { if(vnob[i].ai<=tm) { tm-=vnob[i].ai; td+=vnob[i].ai; ta++; } else break; } ansn=ta; ansd=td; for(i=0;i<vb_top;i++) // bi 不为0 的集合中只要一个被消灭,其他的都会被消灭 { // 这里枚举用自己的武器杀的bi非0集合中的人数 sum+=vb[i].ai; if(sum>m) // sum: 用自己的武器消灭 (i+1)个 bi非0集合中人消耗的耐久度 break; tm=m-sum; // tm: 消灭(i+1)个bi非0集合中人之后剩下的耐久度,这些将拿来消灭 // bi 为0 集合中ai值比较小的那些人 td=sum; // td: 当前消耗的耐久度 ta=vb_top; fr=sumb-vb_top+i+1; // fr: 消灭完bi非0集合中的敌人后剩下的敌人的武器数 ta+=min(nob_top,fr);// 剩下的武器数如果大于bi为0集合中的人数,那么就直接灭完了 for(j=0;j<nob_top-fr;j++)// 用剩下的敌人的武器消灭bi为0集合中的人时尽量消灭ai大的 { if(vnob[j].ai<=tm) // 用剩下的耐久度尽量消灭bi为0集合中ai小的 { tm-=vnob[j].ai; td+=vnob[j].ai; ta++; } else break; } if(ta>ansn) { ansn=ta; ansd=td; } else if(ta==ansn&&td<ansd) ansd=td; } printf("Case %d: %d %d\n",ca++,ansn,ansd); } return 0; }