HDU4415 Assassin’s Creed

题目大意:有n个人,每个人有x,y两个值。x代表干掉他得到的分数,分数和不超过m;y代表干掉他后你能额外干掉多少个,且不计入总分。

求干掉人数最多为多少,以及最小的分。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

考试最后40分钟想出正解贪心,思路太乱没时间码导致20。

直接说正解:优雅的贪心

如果将y为0的放入a集,其余放入b集,那么正解只能有两种情况:

1.只从a中拿。

2.拿走全部的b,剩下将b从小到大排序后去掉最小,然后将b并入a中,再从a中拿。

为什么是这样的?

首先我们可以知道,只要拿走一个b,可以带出全部的b。

这样的话可以想象将bi建成一棵树:

b1->b2->b3

  

       >b4->b5

       

            >b6

假设它是一棵树

假设干掉b2要100块钱,还有一个a2要200块钱。

这样我们可以先干掉b2,花100,然后b1就少了一个儿子,在把a2放进去,就是:

b2->b3

b1->a2

   

   >b4->b5

       

    >b6

这样就是花100块钱干掉a2了。

我们还发现,b1是不能被置换的,因为它没有父亲。

所以正解:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
#define ll long long
int T,n,ac,bc;
ll ax[N],bx[N],by[N],m;
bool cmp(ll x,ll y)
{
    return x<y;
}
int cs;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        cs++;
        printf("Case %d: ",cs);
        scanf("%d%I64d",&n,&m);
        ll sy = 1;
        ac=bc=0;
        for(int i=1;i<=n;i++)
        {
            bc++;
            scanf("%I64d%I64d",&bx[bc],&by[bc]);
            if(!by[bc])
            {
                ax[++ac]=bx[bc];
                bc--;
                continue;
            }
            sy+=by[bc];
        }
        sort(ax+1,ax+1+ac,cmp);
        ll ans1 = 0;
        ll ans2 = 0;
        for(int i=1;i<=ac;i++)
        {
            if(ans2+ax[i]<=m)
            {
                ans1++;
                ans2+=ax[i];
            }else
            {
                break;
            }
        }
        if(!bc)
        {
            printf("%I64d %I64d
",ans1,ans2);
            continue;
        }
        sort(bx+1,bx+1+bc,cmp);
        ll ans3 = sy;
        ll ans4 = bx[1];
        if(ans4>m)
        {
            printf("%I64d %I64d
",ans1,ans2);
            continue;
        }
        for(int i=2;i<=bc;i++)
        {
            ax[++ac] = bx[i];
        }
        sort(ax+1,ax+1+ac,cmp);
        for(int i=1;i<=ac;i++)
        {
            if(ans3>=n)
            {
                ans3=n;
                break;
            }
            if(ans4+ax[i]<=m)
            {
                ans3++;
                ans4+=ax[i];
            }
        }
        if(ans1>ans3||(ans1==ans3&&ans2<ans4))printf("%I64d %I64d
",ans1,ans2);
        else printf("%I64d %I64d
",ans3,ans4);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9749320.html