原题: http://acm.hdu.edu.cn/showproblem.php?pid=4415
题目大意:EA手上有一把武器,耐久度为m,现在他知道前面有n个敌人,杀死第i个敌人ei会降低武器的耐久度ai,但是杀死这个敌人ei可以额外杀死任意bi个人,而杀死这bi个人不降低耐久度 ,问 在保证杀死最多人的情况下,最少需要消耗多少耐久度? 输出最多杀人数和消耗最少的耐久度
贪心策略: 先清楚一点:敌人分为两类,第一类:bi=0的敌人; 第二类:bi>0的敌人,对于bi>0的这类敌人,只要杀了其中一个,其余bi>0的敌人都可以被自动杀死
方案一:手动杀死只杀bi==0的敌人,先把bi=0的敌人按消耗值从小到大排序,然后算出最大杀敌数和被消耗的耐久度;
方案二:先杀死一个bi>0且ai最小的敌人,扣除ai耐久度后,我们可以知道其余bi>0的敌人全都会死,可能还可以附带自动杀死一些bi=0的敌人,然后我们再利用剩下的耐久度去手动杀bi=0的敌人;
但是方案二有一种情况要考虑,如果之后我们利用剩余的耐久度 去 手动杀死一个bi=0的敌人e1,但是e1的损耗值ai很大,但其实我们自己可以手动杀死一个bi>0而ai较小的敌人e2,本来e2是要被自动杀死的,所以我们应该把自动杀死的名额让给消耗值更大的e1
也就是说,先把能被自动杀死的人数求出来(即bi的和,这些人是一定会被自动死的),然后按消耗值从小到大排序,每次优先杀死消耗值小的敌人
比如e1本来是被自动杀死的,并且我的武器耐久度也足够杀到他,但是我们在手动杀死bi=0的这类敌人的时候,发现有个敌人e2的消耗值远大于e1,那我们就选择手动杀死e1,然后让e2被自动杀死
最终结果就是方案一和方案二取最优解,注意一旦杀敌数>=n就可以结束循环,然后杀敌数取n,因为杀敌数不可能大于敌人总数。
如果还不明白可以阅读这位大神的解题报告: http://www.mamicode.com/info-detail-1032227.html
#include<iostream>
#include<cstdio>
#include<algorithm>
#define qwq 0x7fffffff
using namespace std;
struct Ea
{
int ai;
int bi;
}ea[100001],e[100001];//ea 存放b等于0的敌人,e存放全部敌人
int cmp(Ea a,Ea b)//按消耗值从小到大
{
return a.ai<b.ai;
}
int main()
{
int t;
int ca=0;
scanf("%d",&t);//t组测试数据
while(t--)
{
ca++;
int n,m;//敌人的数目,消耗度m
scanf("%d %d",&n,&m);
int pos1=0;//ea的下标
int min=qwq;//b>0并且消耗值最小的敌人p的消耗值
int pos=0;//敌人p所在的下面
int sumbi=0;//自动杀敌数
for(int i=0;i<n;i++)
{
int a,b;
scanf("%d %d",&a,&b);//血量a,消耗度b
if(b==0)
{
ea[pos1].ai=a;//没有炸弹的
pos1++;
}else{//b>0
sumbi=sumbi+b;//全部B相加,这些是可以被自动杀死的人数
if(a<min)
{
min=a;
pos=i;
}
}
e[i].ai=a;
e[i].bi=b;
}
//情况一,只杀b==0的
int m1=m;
int num1=0;
sort(ea,ea+pos1,cmp);//b==0的敌人按消耗值排序
for(int i=0;i<pos1;i++)
{
if(m1>=ea[i].ai)
{
num1++;
m1=m1-ea[i].ai;
}else{
break;
}
}
//情况二,先杀B>0的并且血最低的敌人p
int m2=m-min;//杀了p,扣消耗值
int num2=0;
if(m2>=0)//表示可以杀掉那个人p
{
num2=sumbi+1; //杀掉p之后可以自动杀死的人数
e[pos].ai=-1;//代表p已经死了
sort(e,e+n,cmp);//按消耗值从小到大排序
for(int i=1;i<n;i++)//除了p,遍历每一个还活着的敌人
{
if(num2>=n){//如果杀敌数>=总人数了,直接跳出
break;
}
if(m2>=e[i].ai)//遇到血量少于消耗值的,杀
{
m2=m2-e[i].ai;
num2++;
}else{
break;
}
}
}else{//杀不掉p
num2=-1;
}
num2=num2>n?n:num2;//杀敌数不能大于n
if(num1>num2)//情况一的杀敌数比较多
{
printf("Case %d: %d %d\n",ca,num1,m-m1);
}else if(num1<num2)//情况二的杀敌数比较多
{
printf("Case %d: %d %d\n",ca,num2,m-m2);
}else if(m1>m2){//两种情况的杀敌数相同,比较消耗值大小
printf("Case %d: %d %d\n",ca,num1,m-m1);
}else{
printf("Case %d: %d %d\n",ca,num2,m-m2);
}
}
return 0;
}