这一题这次秋招里好像有道也考到了相同的题。
题解:
dfs或是dp,思路都是相同的。 最坏情况下需要考虑遍历的状态是一样的,从而算法复杂度是一样的。
f[i][j][k]表示对前i-1个敌人直接火球攻击所需的火球攻击数, j,k表示第i-1与i标号的敌人的生命剩余。然后进行状态转移。
遍历i,j,k状态有n*maxh*maxh种状态,而每种最多转移出maxh种状态。
因此时间复杂度为O(n*maxh^3)
AC代码:
#include<iostream>
using namespace std;
#define mylen 11
#define mylife 17
int n, a, b;
int h[mylen];
int f[mylen][mylife][mylife];
int direct_hit[mylife];
int next_hit[mylife];
int direct_hit_life[mylife];
int next_hit_life[mylife];
const int maxbound = mylife * mylen;
void init()
{
for (int i = 0; i < n; ++i)
{
for (int j = 0; j <= h[i-1]; ++j)
{
for (int k = 0; k <= h[i]; ++k)
{
f[i][j][k] = maxbound;
}
}
}
for (int i = 1; i <= mylife; ++i)
{
direct_hit[i] = (i - 1) / a + 1;
direct_hit_life[i] = i * a;
next_hit[i] = (i - 1) / b + 1;
next_hit_life[i] = i * b;
//cout << direct_hit[i] << '\t';
}
}
void process()
{
f[1][h[0]][h[1]] = 0;
int min_hit, max_hit, tmp_j, tmp_k, tmp_num, i;
for (i = 1; i < n-1; ++i)
{
for (int j = 0; j <= h[i - 1]; ++j)
{
min_hit = next_hit[j];
for (int k = 0; k <= h[i]; ++k)
{
max_hit = ((direct_hit[k]>min_hit)?direct_hit[k]:min_hit);
for (int num = min_hit; num <= max_hit; ++num)
{
tmp_num = f[i][j][k] + num;
tmp_j = ((k > direct_hit_life[num]) ? (k-direct_hit_life[num]) : 0);
tmp_k = ((h[i + 1] > next_hit_life[num]) ? (h[i + 1] - next_hit_life[num]) : 0);
if (f[i + 1][tmp_j][tmp_k] > tmp_num)
{
f[i + 1][tmp_j][tmp_k] = tmp_num;
// cout << tmp_num << '\t';
}
}
}
}
}
int result = maxbound;
for (int j = 0; j <= h[i]; ++j)
{
if (result > f[i][0][j] + next_hit[j])
{
result = f[i][0][j] + next_hit[j];
}
}
/* for (int j = 0; j <= h[n - 2]; ++j)
{
if (result > f[n - 1][j][0])
{
result = f[n - 1][j][0];
}
}*/
printf("%d\n", result);
/* cout << endl;
for (int i = 1; i < n; ++i)
{
for (int j = 0; j <= h[i - 1]; ++j)
{
for (int k = 0; k <= h[i]; ++k)
{
cout << f[i][j][k] << '\t';
}
}
cout << endl;
}*/
}
int main()
{
scanf("%d%d%d", &n, &a, &b);
for (int i = 0; i < n; ++i)
{
scanf("%d", &h[i]);
++h[i];
}
init();
process();
return 0;
}