HDU 4415 Assassin’s Creed(贪心)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4415

刚看见这个题目觉得很简单(其实不是),直接可以把整个集合分成两部分,一部分是有兵器的,一部分是没有兵器的

答案就是下面两种情况下最优的那个

第一种情况:只杀死所有没有兵器的敌人

第二种情况:有兵器的全部杀死,然后用得到的兵器和剩下的钱去杀没有兵器的那个集合,因为有兵器的这个集合只要能杀死一个,那么就全部都能杀死


当然这个题目没有那么简单,不能想当然的去直接用上面两种情况去做,当然第一种情况没什么好说的,关键是第二种情况,这里要小心,不能想当然去做

不过这里处理还是用的贪心思路

首先杀死有兵器的,肯定先用钱杀死有兵器中花费最小的那个,然后接着用兵器杀死整个有兵器的集合中的所有人,然后计算出当前获得的兵器数目去从

后向前(按照杀死需要的花费排序)去杀,完成之后开始用钱从前面开始杀,这里用钱杀不是真正意思上的用钱杀,意思是到花钱的时候了,现在假设要

杀没有兵器的a,那么用杀死a的花费和在有兵器集合里面用兵器杀掉的花费最小的那个花费比,如果小,那么直接用钱杀死,否则花钱换用兵器杀死的那

个人的兵器,也就是说本来用兵器杀死你的,现在我又不想了,那么用钱杀死你,换回杀死你的兵器去杀死价值更大的人,这时候这个兵器是不是用来杀

死a呢,当然可能不是了,要用这个换回来的兵器杀死无兵器集合里面当前没死的要杀死代价最大的那个人。

总之这个题目是一步步贪心下去,不能放过每一个最优的条件。


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define maxn 110000
struct point
{
    int a;
    int b;
}first[maxn];
int second[maxn],num1,num2,n,m,ans1,money1,ans2,money2;
int cmp(const point &a,const point &b)
{
    return a.a < b.a;
}
bool first_case()
{
    int i,j,k,p=m,num,temp1,pos;
    if(num1<=0 || first[0].a > m)
    return false;
    p-=first[0].a;
    num=0;
    for(i=0;i<num1;i++)
    num+=first[i].b;
    num-=num1;
    num++;
    ans1=num1;
    money1=first[0].a;
    if(num >= num2)
    {
        ans1+=num2;return true;
    }
    temp1=num2;
    temp1-=num;
    ans1+=num;
    pos=1;
    for(i=0;i<temp1 && (p>=first[pos].a || p>=second[i]); )
    {
        if( pos <num1 && first[pos].a <= second[i])
        money1+=first[pos].a,temp1--,p-=first[pos].a,pos++;
        else
        money1+=second[i],p-=second[i],i++;
        ans1++;
    }
    return true;
}
int second_case()
{
    int i=0,j,k,p=m;
    while(i< num2 && p>=second[i])
    {
        ans2++;
        money2+=second[i];
        p-=second[i];
        i++;
    }
    //printf("%d %d\n",ans2,money2);
    return 0;
}
int main()
{
    int t,i,j,a,b,k=0;
    scanf("%d",&t);
    while(t--)
    {
        num1=num2=0;
        ans1=ans2=0;
        money1=money2=0;
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            if(b==0)
            second[num2++]=a;
            else
            first[num1].a=a,first[num1++].b=b;
        }
        sort(first,first+num1,cmp);
        sort(second,second+num2);
        second_case();
        if(first_case()==false)
        {
            printf("Case %d: %d %d\n",++k,ans2,money2);
            continue;
        }
        if(ans1 > ans2)
        {
            printf("Case %d: %d %d\n",++k,ans1,money1);
        }
        else
        {
            if(ans1==ans2) printf("Case %d: %d %d\n",++k,ans1,money1 < money2 ? money1 : money2);
            else
            printf("Case %d: %d %d\n",++k,ans2,money2);
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值