打小兵
题目描述:
一共有20个人,每个人的hp~( 1,60 ) 每次进行一次攻击,造成9 3 1的攻击,对三个人。问最少攻击几次可以把所有的人都干掉。
题解:
20个人,每个人60种可能,不能表示完。总感觉有贪心策略,但是边界条件搞不掉。于是答案竟然还是dp暴力。只是dp【a】【b】【c】表示用几个9 3 1,对于每一个数,枚举情况看它怎么拆分,是一个数一个数的去考虑,而不是一次931一次931的去用。注意很重点的是,一个数拆分的总个数要少于总的使用次数,这样一定可以把他们分在不同的组里面。可以判定m次来写,也可以直接dp
重点:
关键是思维的变化。不再是一次一次的去用,而是一个数一个数的拆分干掉。然后为了满足题意,再添加限定条件。之后由于9 3 1只有三个数,因此描述状态就好描述了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const int maxn = 101;
const int INF = 1e6 +10;
int dp[21][maxn][maxn][maxn];
int x[maxn], n;
class MutaliskEasy//没有用判定,其实判定思路更好写
{//我是用的dp的值表示的到达此状态限定的至少得次数。
public:
int minimalAttacks(vector<int> t)
{
n = t.size();
REP(i, 0, n)
{
x[i + 1] = t[i];
}
REP_D(i, 0, 100)//初始化,不能达到此状态
{
REP_D(j, 0, 100)
{
REP_D(k, 0, 100)
{
REP_D(z, 0, n)
{
dp[z][i][j][k] = INF;
}
}
}
}
dp[0][0][0][0] = 0;//解决0个用了0个931
REP_D(i, 1, n)//更新的dp
{
for(int a = 0; a <= 100; a++)
{
for(int b = 0; b <= 100; b++)
{
for(int c = 0; c <= 100; c++)
{
if(dp[i-1][a][b][c]==INF)//abc是合法的时候
continue;//下面拆分数字,注意,枚举9几个3几个,注意都要多枚举一次,因为9的时候可能搞的8
for(int aa = 0; aa*9 <= x[i] + 9; aa++)
{
for(int bb = 0; aa*9+bb*3 <= x[i] + 12; bb++)
{
int cc = x[i]-aa*9-bb*3;
cc = max(0, cc);
if(a+aa<=100&&b+bb<=100&&c+cc<=100)
{//转移方程
dp[i][a+aa][b+bb][c+cc]=min(dp[i][a+aa][b+bb][c+cc], max(aa+bb+cc,dp[i-1][a][b][c]));
}
}
}
}
}
}
}
int ans = INF;//把n个都干掉,并且再算上限定次数
REP_D(a, 0, 100)
{
REP_D(b, 0, 100)
{
REP_D(c, 0, 100)
{
int tmp = max(a, b);
tmp = max(tmp, c);
tmp = max(tmp, dp[n][a][b][c]);
ans = min(ans, tmp);
}
}
}
return ans;
};
};
int main()
{
freopen("13Min.txt", "r", stdin);
//freopen("1out.txt", "w", stdout);
int tt;
vector<int> y;
while(scanf("%d", &tt) != EOF)
{
y.push_back(tt);
}
MutaliskEasy a;
cout << a.minimalAttacks(y) << endl;
return 0;
}