hdu 4415 Assassin’s Creed
这个题目,比赛的时候第一感觉就是贪心,但是一直没有找到办法贪心,写了100+行的代码也wa了,这是我见过的最牛b的贪心了; 比赛之后问了别人的思路,自己再细心的想想就想出来了,虽然别人跟我讲思路,我都没有听明白,T_T,貌似网上的代码很多就是错误的,我这个代码应该不会错,ac之后我把网上的数据都过了,自己还和别人对拍了随机数据,没问题……
分组1:b==0 的为一组
分组2: b!=0 为一组
结论:因为分组2,如果我们杀掉了其中一个,由于他们的武器都大于0,所以贪心的话肯定要把这组全部杀掉…… 故 组2要么一个不杀,要么都要杀掉
1. 组2一个不杀,那么组1从小到大开始杀,得到答案 cnt1 cost1
2. 组2都杀掉,问题都来了,组2用什么杀最好呢? 可以使用他们自己提供的武器 , 也可以消耗攻击值,如何贪心是这道题的难点。
谈谈我的思路: 首先我假设组2内除了开始消耗攻击值杀掉a最小的人外,其他的全部都用武器杀; 然后我们把剩下的武器杀掉那些组1内的a最大的人,接下来就得必须用攻击值了。 我 是用个 point 始终是指向 组1中还没有杀掉的a的最大的人,然后i从0 开始(即a由小到大)扫描,如果当前i指向的是组1的人,那么杀掉它肯定是最优的,小于i的都被傻掉了,再也没有a比i的a小了。 如果当前i指向的是组2的人,那么贪心的话肯定要用攻击值杀掉他,然后撤销之前用武器杀他,从而我们就获得了一个武器然后再贪心杀掉 point指向的人(point 始终指向的是 组1中没有被杀的a的最大的人)
实践证明: 测试数据没有出现讨论1的情况,也就是测试数据都是全部杀掉了组2中的人,数据确实弱了
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> #include <set> #include <map> #include <algorithm> using namespace std; #define pa system("pause") const int maxn=100010; const int inf=0x3fffffff; struct node { int a,b; }p[maxn]; int cmp(node c1,node c2) { return c1.a < c2.a; } int main() { //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); int T,n,m,ca=1; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d%d",&p[i].a,&p[i].b); sort(p,p+n,cmp); int start=-1,cost1=0,cnt1=0,cost2=0,cnt2=0,weapon=0; for(int i=0;i<n;i++) if(p[i].b!=0) { cnt2++; weapon+=p[i].b; if(start==-1) start=i; }else if(cost1+p[i].a<=m){ cost1+=p[i].a,cnt1++; } if(start==-1||m<p[start].a) { printf("Case %d: %d %d\n",ca++,cnt1,cost1); continue; } int point=n-1; weapon=weapon-cnt2+1; cost2=p[start].a; while(point>=0&&weapon>=0) { if(p[point].b==0) { if(weapon==0) break; else cnt2++,weapon--; } point--; } for(int i=0;i<=point&&p[i].a+cost2<=m;i++) if(i!=start) { cnt2++,cost2+=p[i].a; if(p[i].b!=0) { point--; while(point>=i&&p[point].b!=0) point--; } } if(cnt1>cnt2||(cnt1==cnt2&&cost1<cost2)) printf("Case %d: %d %d\n",ca++,cnt1,cost1); else printf("Case %d: %d %d\n",ca++,cnt2,cost2); } return 0; }