首页 > 代码库 > [贪心] hdu 4415 Assassin’s Creed

[贪心] hdu 4415 Assassin’s Creed

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4415

题目意思: 

要杀死n个敌人,每个敌人有两个属性a和b,a表示杀他所需要的能力值,b表示杀掉他后可以免费再杀b个敌人。告诉初始能力值,求能杀的最多的敌人,及杀掉那么多敌人的最小花费。

解题思路:

分类+贪心

这道题比较难,也比较经典。好题。

首先把敌人按b值是否为零分成两类A和B。A类表示b值不为零,B类表示b值为零。A、B分别按a从小到大排序

首先明确:

1、如果要杀A类,至少需要A[0].a能力值,并且可以把A类全部杀掉,而且还有多的免费名额可以再杀B类。

2、如果能杀A[0].a,则无论是花费杀A类,还是用免费名额杀A类,总的得到的杀B类的免费名额是不变的。


考虑三种情况:

1、先尽可能的杀B类,然后剩余的能力看能不能杀掉A中a值最小的A[0],然后把A类全部杀掉,再用免费的名额杀B。

2、先杀A[0],然后把A类全部杀掉,然后多的免费名额再杀B类,然后用多的花费来杀B类。

3、先杀A[0],此时不是用免费名额杀A类,而是比较A类和B类哪个a值较小,然后可能用花费能力值来杀A类,多出的那个免费名额来杀B类。

5 4

1 1

2 2

3 0

4 0

5 0

答案:5 3   如果要杀A类,至少要花费1,并且能杀A类的话,A类肯定可以全部杀完。此时得到的免费名额都是2(除开A的花销),而此时选择用花费来杀掉A类的2 2,这样就避免了花费更多的能力值去杀a值比较大的B类。

代码解释的很详细。

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#include<cmath>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

struct Inf
{
    int a,b;
};
vector<Inf>A,B;
int n,m;

bool cmp(Inf aa,Inf bb)
{
    return aa.a<bb.a;
}

void cal(int &num,int &cost)
{
    int num1=0,cost1=0,num2=0,cost2=0,sum=0;  //num1,cost1表示先选A类 num2,cost2表示先尽可能的选B类
    int i=0,j=0,p=B.size()-1; //p表示B类的最后一个元素

    //printf("p:%d\n",p);

    while(i<B.size()&&m-cost2>=B[i].a) //先尽可能的选B类
    {
        cost2+=B[i].a;
        num2++;
        i++;
    }
    i=0;
    if(i<A.size()&&m>=A[i].a) //一开始就选A类,多的再选B类
    {
        num1+=A.size();
        cost1=A[i].a;
        while(i<A.size())
            sum+=A[i++].b;
        sum-=A.size()-1;
    }
    i=0;
    if(i<A.size()&&m-cost2>=A[i].a) //把B选完后,再选A类看能不能把A类全部搞完
    {
        num2+=A.size();
        cost2+=A[i].a;
        num2+=sum;  //如果行,一定可以选sum个  //至此先选B类的情况已经全部算完了
        if(num2>n)
            num2=n;
    }
    while(p>=0&&sum)
        p--,sum--,num1++;  //先选A类,再选B类的情况,还有可能继续支付花费来选B类
    if(p<0) //说明先选A类,再选B类的情况可以不用花费就把B类全搞定  注意如果要消灭A类,至少要花费A[0].a
    {
        if((num1>num2)||(num1==num2&&cost1<cost2))
            num=num1,cost=cost1;
        else
            num=num2,cost=cost2;
        return ;
    }
    //printf("num1:%d cost1:%d num2:%d cost2:%d sum:%d p:%d\n",num1,cost1,num2,cost2,sum,p);
    //system("pause");

    //再考虑A类中,是考虑用免费的,还是用花费的,然后多出来的那个免费去搞B类
    for(i=1,j=0;j<=p&&i<A.size()&&m-cost1>=min(A[i].a,B[j].a);)
    {
        if(A[i].a<=B[j].a) //选择花费来消灭当前这个A类,同时腾出来一个消灭B类
        {                  //注意总的量不变
            cost1+=A[i].a;
            p--;
            i++;
            num1++;

        }
        else     //用花费来消灭B类
        {
            cost1+=B[j].a;
            j++;
            num1++;

        }
    }
    //printf("::cost1:%d p:%d\n",cost1,p);
    while(j<=p)
    {
        if(m-cost1>=B[j].a)
        {
            num1++;
            cost1+=B[j].a;
            j++;
        }
        else
            break;

    }
    //printf("num1:%d cost1:%d num2:%d cost2:%d sum:%d p:%d\n",num1,cost1,num2,cost2,sum,p);
    //system("pause");

    if((num1>num2)||(num1==num2&&cost1<cost2))
        num=num1,cost=cost1;
    else
        num=num2,cost=cost2;
    return ;
}

int main()
{
    //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   int t,kcas=0;

   scanf("%d",&t);
   while(t--)
   {
       scanf("%d%d",&n,&m);
       A.clear();
       B.clear();

       for(int i=1;i<=n;i++)
       {
           Inf temp;
           scanf("%d%d",&temp.a,&temp.b);
           if(temp.b)
                A.push_back(temp);
           else
                B.push_back(temp);
       }
       sort(A.begin(),A.end(),cmp);
       sort(B.begin(),B.end(),cmp);
       int num,cost;
       cal(num,cost);

       printf("Case %d: %d %d\n",++kcas,num,cost);
   }
    return 0;
}
/*
5 4
1 1
2 2
3 0
5 0
6 0

keys:5 3
*/




[贪心] hdu 4415 Assassin’s Creed