HDU 4415 Assassin’s Creed(贪心)

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

题意:一个杀手,有m的攻击力,n个敌人。每个敌人有两个属性ai,bi,表示杀死这个敌人需要ai的攻击力,杀死该敌人后,可以再免费杀死bi个其他的敌人而不花费自己的攻击力。求最多可以杀死多少个敌人?在此基础上花费的最少的攻击力是多少?

思路:将所有的敌人分为两类A和B,A是bi值不为0的,B是bi值为0的:

(1)优先杀B类的:用攻击力杀掉尽可能多的B类的,剩余的攻击力若还能杀A类的某一个,则显然,必能将A类得全部干掉,并且还可能有一些可以免费的还可以再接着杀掉B的一些;

6 5

1 0

1 0

1 0

1 0

1 0

5 1

像这组数据,显然优先杀掉B类的是最划算的。。。。

(2)优先杀掉A类的:由于A类的你能干掉其中一个,就可以将A类全部干掉,而且还可以有剩余的免费的还能接着干掉B类的,若攻击力还有,还可以接着杀掉B类得一些,比如这组数据:

6 1

1 5

1 0

1 0

1 0

1 0

1 0

你发现干掉A中的一个后可以用免费的将B类全部干完。这样貌似问题就解决了,但是还有这种情况:

5 7
3 2
4 1
5 0
6 0
7 0

这组数据的答案是5 7.首先用7的攻击力将A类的干掉,用干掉A类得到的3的免费的将B类干掉,也就是说,A类的一些不一定用干掉A的第一个后得到的免费名额。这样的话,首先干掉A类ai值最小的,然后将A类剩余的和B类的一起考虑,每次用自己的攻击力干掉其中ai值最小的。

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 #include <algorithm>
  6 #define min(x,y) ((x)<(y)?(x):(y))
  7 #define max(x,y) ((x)>(y)?(x):(y))
  8 using namespace std;
  9 
 10 struct node
 11 {
 12     int a,b;
 13 
 14     node(){}
 15     node(int _a,int _b)
 16     {
 17         a=_a;
 18         b=_b;
 19     }
 20 };
 21 
 22 const int INF=1000000005;
 23 const int MAX=100005;
 24 vector<node> A,B;
 25 int n,m,num=0;
 26 int C;
 27 
 28 int cmp(node a,node b)
 29 {
 30     return a.a<b.a;
 31 }
 32 
 33 void cal(int &Num,int &Cost)
 34 {
 35     int cost1=0,cost2=0,num1=0,num2=0,sum=0,p=B.size()-1,i,j;
 36 
 37 
 38     for(i=0;i<B.size();i++) if(m-cost1>=B[i].a)
 39     {
 40         num1++;
 41         cost1+=B[i].a;
 42     }
 43 
 44     if(A.size()&&A[0].a<=m)
 45     {
 46         cost2+=A[0].a;
 47         num2=A.size();
 48         for(i=0;i<A.size();i++) sum+=A[i].b;
 49         sum-=(A.size()-1);
 50     }
 51 
 52     if(A.size()&&A[0].a<=m-cost1)
 53     {
 54         cost1+=A[0].a;
 55         num1+=A.size();
 56         num1+=sum;
 57         if(num1>n) num1=n;
 58     }
 59 
 60     while(sum>0&&p>=0) sum--,p--,num2++;
 61 
 62     if(p<0)
 63     {
 64         if(num2>num1||num2==num1&&cost2<cost1)
 65         {
 66             Num=num2;
 67             Cost=cost2;
 68         }
 69         else
 70         {
 71             Num=num1;
 72             Cost=cost1;
 73         }
 74         return;
 75     }
 76     for(i=1,j=0;i<A.size()&&j<=p&&m-cost2>=min(A[i].a,B[j].a);)
 77     {
 78         if(A[i].a<=B[j].a)
 79         {
 80             cost2+=A[i].a;
 81             num2++;
 82             p--;
 83             i++;
 84         }
 85         else
 86         {
 87             cost2+=B[j].a;
 88             num2++;
 89             j++;
 90         }
 91     }
 92     while(j<=p)
 93     {
 94         if(m-cost2>=B[j].a)
 95         {
 96             cost2+=B[j].a;
 97             num2++;
 98             j++;
 99         }
100         else break;
101         j++;
102     }
103     if(num2>num1||num2==num1&&cost2<cost1)
104     {
105         Num=num2;
106         Cost=cost2;
107     }
108     else
109     {
110         Num=num1;
111         Cost=cost1;
112     }
113 }
114 
115 int main()
116 {
117     for(scanf("%d",&C);C--;)
118     {
119         A.clear();
120         B.clear();
121         scanf("%d%d",&n,&m);
122         int i;
123         node p;
124         for(i=1;i<=n;i++)
125         {
126             scanf("%d%d",&p.a,&p.b);
127             if(p.b) A.push_back(p);
128             else B.push_back(p);
129         }
130         sort(A.begin(),A.end(),cmp);
131         sort(B.begin(),B.end(),cmp);
132         int Num,Cost;
133         cal(Num,Cost);
134         printf("Case %d: ",++num);
135         printf("%d %d\n",Num,Cost);
136     }
137     return 0;
138 }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值