首先上原题:
描述
在一个类似于炉石的卡牌对战游戏中,玩家当前有m张卡牌,每张卡牌的伤害分别为d1、d2、…、dm。
玩家可以控制这m张卡牌中的一些攻击电脑,也可以控制其中一些不攻击电脑。当然也可以全部卡牌攻击电脑,也可以全都不攻击电脑。
电脑的血量是a,每1点伤害就会扣减电脑1点血量,电脑的血量最多只会被扣减到0,如果血量减到负数那么也算作0。
问:经过一个回合的攻击后,电脑剩余的血量有多少种可能?
输入
一个正整数n,表示有n组案例。
每组案例先是两个正整数m和a,分别表示卡牌的数量和电脑的血量。(m<=100,a<=10000)
然后是m个正整数d1、d2、…、dm,分别表示这m张卡牌的攻击力。(di<=1000)
输出
针对每组案例,输出一个整数,表示经过一个回合的攻击后,电脑剩余的血量有多少种可能。
每组案例输出完都要换行。
样例输入
2
2 100 3 5
2 100 10 100
样例输出
4
3
Braoadcloak大佬的版本:https://blog.csdn.net/Broadcloak/article/details/103221336
Broadcloak版本:
for (int i = a; i >= 0; i--)//从高往低看
{
if (b[i] == true)
{
if (i + d < a)b[i + d] = true;
else b[a] = true;//超出生命值
}
}
b数组元素下标并不能和实际血量相关联(相当于是倒序排列了),理解这段代码花了挺长时间。尝试复现的时候遇到了点问题。
修改后的版本:
for (int i = 0; i <=a; i++)
{
if (blood[i])//存在血量为i的可能性,可以打牌(如果不打牌,血量还是为i)
{
if (i-d>0 )blood[i - d] = true;//判断打出这张牌后,血量是否为正值
else blood[0] = true;
}
}
修改后的版本blood元素下标与实际血量相关联(blood[i]为true代表存在血量i的这种可能)
在写这段代码的时候遇到了另一个很常见的错误,存档一下。
for (int i >= a; i <=0; i--)
{
if (blood[i])
{
if (i-d>0 )blood[i - d] = true;
else blood[0] = true;
}
}
两个版本的区别在于,i循环的方向不同(一个是从0到a,一个是从a到0)。后一个版本的错误在于,修改blood[i1-d]为true后,i继续减小,i2等于i1-d时blood[i2]必定为true....导致blood[i1-n*d]都为true。正确版本则是修改blood[i1-d]为true后,i增大,修改的是朝i循环相反方向的值,就不会有问题啦~
总结:在循环变量和数组元素下标挂钩且要修改非当前循环变量值下标元素的情况下,循环变量增大或减小的方向要和修改非当前循环变量值下标元素的方向相反。例如:i从0循环到100,可以修改[i-x]元素,不能修改[i+x]元素。