hdu 4415 Assassin’s Creed

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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值