这题最困难的方面是战斗的策略。

假设我们有\(i\)个士兵,兵营的血量为\(z\),我们的对手有\(j\)个士兵,设\(dp[i][j][k]\)为我们赢得战斗的最小回合数(如果不可能,则为无穷)。计算时,按照题目的步骤一步步模拟递推就行了。

但是如果只是这样的话,可能会出现环,或者无穷的状态(比如\(j\)不断往上增长),所以为了解决这一点,需要将\(j>100\)的情况全部舍弃。

具体细节请看代码

#include<bits/stdc++.h>
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
int dp[55][2005][55];
class BarracksEasy {
public:
    int attack(int myUnits, int barHp, int unitsPerRound) {
        clr(dp,60);
        for(int i=1;i<=myUnits;i++)dp[i][0][0]=0;
        for(int i=1;i<=myUnits;i++)
            for(int z=0;z<=barHp;z++)
                for(int j=0;j<=100;j++){
                    for(int k=0;k<=i;k++){//多少士兵去攻击对面的大本营 
                        int bH=max(0,z-k);
                        int op=max(0,j-i+k);
                        int mine=max(0,i-op);
                        if(bH>0)op+=unitsPerRound;
                        if(k==0 && bH>0)continue;//如果没有士兵去攻击大本营,那么状态转移会出现环,直接跳过 
                        if(op<=100)dp[i][j][z]=min(dp[i][j][z],dp[mine][op][bH]+1);
                    }
                }
        if(dp[myUnits][0][barHp]>1e9)return -1;
        return dp[myUnits][0][barHp];
    }
};