hdu4415 Assassin’s Creed


    这题是明显的贪心,首先在读取数据时把敌人按有刀和无刀分成两类,刚开始有两种贪心决策,只杀无刀的人和杀掉所有有刀的人,然后比较这两种决策,选出最优解。

    第一种决策很容易求出,就不说了,重点来讨论第二种。对于有刀之人,肯定先选血量最少的人来杀,然后得到他的刀,如果我们用得到的刀继续杀有刀之人,如此杀下去,那么我们肯定可以杀掉所有有刀的人了,然后用得到的刀还可以继续去杀没有刀的人。当然如果按照这种方式能杀掉所有剩余的人的话,也就是说不需要用自己的刀再去杀,无疑这就是最优的了,但如果用得到的刀不能杀掉所有的人呢?这种情况我们就要继续贪心了,既然有一部分人是必须要用自己的刀去杀,那么我们就应该选血量少的去杀,因此我们就要综合比较有刀之人和无刀之人,选出血量最小的那些人(即用得到的刀杀不到的人),然后用自己的刀去杀,解决这部分人之后,其它的人是肯定可以杀完的(由上面的讨论可知)。分析到这里,这道题也就可以完整解决了,下面具体看代码。

 

 

#include<iostream>
#include<cstdio>
#include<algorithm> 
using namespace std;
const int maxn=100005;
int a[maxn],b[maxn];
//a[i]记录有刀之人的血量 ,b[i]记录无刀之人的血量
int n,m;
int cnt1,cnt2;//有刀之人与无刀之人的人数
int sword;//记录刀的数量 

int main()
{
    int t,i,j,x,y;
    int ans,left;
    int ans1,left1;//能杀的人数和剩余的血量(分两种情况) 
    
    scanf("%d",&t);
    for(i=1;i<=t;i++)
    {
        scanf("%d%d",&n,&m);
        cnt1=cnt2=sword=0;
        for(j=1;j<=n;j++)
        {
            scanf("%d%d",&x,&y);
            if(y)
            {
                sword+=y;
                a[cnt1++]=x;
            }
            else
                b[cnt2++]=x;
        }
        sort(a,a+cnt1);
        sort(b,b+cnt2);
        //只杀无刀之人 
        j=0;
        ans=0;
        left=m;
        while(left>=0&&j<cnt2)
        {
            if(left>=b[j])
            {
                left-=b[j++];
                ans++;
            }
            else
                break;
        }
        //杀完有刀之人
        if(m>=a[0])
        {
            if(sword>=n-1)//能用得到的刀直接杀掉所有人
            {
                if(ans<n)
                {
                    ans=n;
                    left=m-a[0];
                }
                else if(ans==n&&left<m-a[0])
                    left=m-a[0];
                printf("Case %d: %d %d\n",i,ans,m-left);
                continue;
            } 
            int k=n-1-sword;//另外还需要用自己的刀杀死的人数
            
            //此处继续贪心:既然无论如何这k个人是必须要杀的,
            //那么我们就应该综合比较有刀的和无刀的,选血量最小的杀
            int *temp= new int[k];
            x=1;y=0;j=0;
            a[cnt1]=b[cnt2]=100000000;
            while(j<k)
            {
                if(a[x]<b[y])
                    temp[j]=a[x++];
                else
                    temp[j]=b[y++];
                j++;
            }
            j=0;
            ans1=1+sword;
            left1=m-a[0];
            while(j<k&&left1>=0)
            {
                if(ans1==n)
                    break;
                if(left1>=temp[j])
                {
                    left1-=temp[j++];
                    ans1++;
                }
                else
                     break;
            }
            if(ans1>ans)
            {
                ans=ans1;
                left=left1;
            }
            else if(ans1==ans&&left<left1)
                left=left1;
            delete []temp;
        }
        printf("Case %d: %d %d\n",i,ans,m-left);
    }
    //system("pause");
    return 0;
} 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值