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