题目来源:acm.njupt.edu.cn
炉石传说
炉石传说是暴雪公司推出的一款卡牌游戏,游戏中玩家可以通过召唤仆从和施放法术的方式两两对战。每一个仆从又两项数值:攻击力和生命值。比如火车王这张牌,数值为6-2表示攻击力为6,生命值为2。在游戏过程中,如果两个仆从进行一次战斗,那么战斗之后血量将被扣除对方攻击力大小的数值,而攻击力不会改变。一旦血量小于等于0,仆从就死亡而从战场上移除。现在你有n个仆从,对手有m个仆从,你可以在一个回合战斗中消灭对方所有仆从吗?(一回合中每个仆从最多攻击一次,对手不会发动攻击)
Iuput:
第一行:一个正整数T,表示T组数据
每组数据的第一行是两个整数n,m,接下来n+m行每行又两个整数a,b表示仆从的攻击力和血量
Output:
如果可以消灭对方所有仆从,输出YES
否则输出NO
Sample Input
2
1 2
2 3
1 1
3 1
2 2
2 3
1 1
3 2
3 1
Sample Output
NO
YES
思路:
1.要消灭对方全部仆从,最起码的条件是我方仆从的数量大于等于对方仆从数量(即n>=m)
2.满足条件1时,我方仆从的攻击力与对方仆从的生命值都按从大到小的顺序排列,然后依次比较。若我方仆从攻击力大于等于对方仆从生命值,则继续比较。否则从剩下的仆从中选一个合适的一起攻击。(需要将已经攻击过的仆从做标记)。
(选择合适的仆从时,应该是 当前仆从的攻击力+再选择的仆从的攻击力>=对方仆从生命值
如 攻击力为 4 3 3 1 生命值为 5 3 2,选攻击力为3的仆从时就不能得到正确结果。选择过程见代码)
自定义函数的实现:
bool Judge(int *a,int *b,int n,int m)
{
bool *as=new bool[n]; //两个BOOL类型数组标记已经攻击过的仆从
bool *bs=new bool[m];
int i,j,k;
if(n<m)
{
return false;
}
else
{
for(i=0;i<n;i++)
{
as[i]=false;
}
for(j=0;j<m;j++)
{
bs[j]=false;
}
PaiXu(a,n); //自定义的排序函数,将我方仆从的攻击力以及
PaiXu(b,m); //对方仆从的生命值从大到小排序
i=0;j=0;
while(i<n&&j<m)
{
if(as[i]==true)
{
i++;
}
if(a[i]>=b[j])
{
as[i]=true;
bs[j]=true;
i++;
j++;
}
else
{
for(k=i+1;k<n&&as[k]==false;k++) //最关键的地方:当我方攻击力最大的仆从
{ //小于对方生命值最大的仆从时,需要从剩
if(a[i]+a[k]<b[j]) //下的仆从中选择一个攻击力合适一起攻
{break;
}
}
a[i]+=a[k-1]; //如果在上一个循环中没有满足
as[k-1]=true; //条件a[i]+a[k]<b[j]的数据,则选择当前
n--; //攻击力最小的
if(n-i-1<m-j-1)
{
return false;
}
}
}
}
return true;
}
void PaiXu(int *a,int n)
{
int i,j,x;
for(i=1;i<n;i++)
{
j=i;
x=a[j];
while(a[j-1]<x&&j>0)
{
a[j]=a[j-1];
j--;
}
a[j]=x;
}
}
主函数的实现:
#include"iostream" using namespace std; bool Judge(int *a,int *b,int n,int m); void PaiXu(int *a,int n); int *a,*b; int q; int main() { int t; cin>>t; while(t--) { int n,m,i,j; cin>>n>>m; a=new int[n];b=new int[m]; for(i=0;i<n;i++) { cin>>a[i]>>q; //我方仆从,只用记录攻击力 } for(j=0;j<m;j++) { cin>>q>>b[j]; //对方仆从,只用记录生命值 } if(Judge(a,b,n,m)==true) { cout<<"YES"<<endl; } else { cout<<"NO"<<endl; } } return 0; }