Description
有 n n 个怪物编号~ n n ,每次可以攻击~ n−1 n − 1 中任意一个怪物,第 i i 个怪物的血量为,一个怪物必须血量为负值才算死亡,但是死亡的怪物依旧可以攻击,如果对第 i i 个怪物攻击,对第的怪物会造成 a a 点伤害,对第和第 i+1 i + 1 个怪物造成 b b 点伤害,问最少多少次攻击可以让所有怪物死亡,并输出被攻击怪物的编号
Input
第一行三个整数,之后输入 n n 个整数 (3≤n≤10,1≤b<a≤10,1≤hi≤15) ( 3 ≤ n ≤ 10 , 1 ≤ b < a ≤ 10 , 1 ≤ h i ≤ 15 )
Output
输出最少攻击次数和每次攻击的怪物编号
Sample Input
3 2 1
2 2 2
Sample Output
3
2 2 2
Solution
攻击先后次序无关,只需考虑对每只怪物攻击几次即可,故顺序考虑攻击,即如果当前对第 i i 个怪物攻击,那么要求前个怪物都已经死亡,为避免计算繁琐,把每个怪物的血量加一,这样只要怪物血量清零则死亡,以 dp[i][j][k] d p [ i ] [ j ] [ k ] 表示当前攻击第 i i 个怪物,前个怪物已经死亡,第 i−1 i − 1 个怪物血量为 j j ,第个怪物的血量为 k k 的条件下需要的最少攻击次数,则有,考虑对第 i i 个怪物的攻击次数,首先必须让第个怪物死亡才能去攻击第 i+1 i + 1 个怪物,所以至少要攻击 x=⌈jb⌉ x = ⌈ j b ⌉ 次,最多次数是使得第 i i 个怪物和第个怪物都死亡,打死第 i i 个怪物需要攻击次,打死第 i+1 i + 1 个怪物需要攻击 z=⌈hi+1b⌉ z = ⌈ h i + 1 b ⌉ 次,那么最多攻击次数即为 max(y,z) m a x ( y , z ) ,枚举攻击次数 l l ,则第个怪物血量变成 jj=max(0,k−a∗l) j j = m a x ( 0 , k − a ∗ l ) ,第 i+1 i + 1 个怪物血量变成 kk=max(0,hi+1−b∗l) k k = m a x ( 0 , h i + 1 − b ∗ l ) ,进而有转移:
dp[i+1][jj][kk]=max(dp[i+1][jj][kk],dp[i][j][k]+l) d p [ i + 1 ] [ j j ] [ k k ] = m a x ( d p [ i + 1 ] [ j j ] [ k k ] , d p [ i ] [ j ] [ k ] + l )
dp[n][0][0] d p [ n ] [ 0 ] [ 0 ] 即为答案,对每个怪物的具体攻击次数在转移时记录转移到当前状态的前继状态即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef pair<int,int>P;
int n,a,b,h[11],dp[11][22][22];
P pre[11][22][22];
#define INF 200
void output(int id,int x,int y)
{
if(id==1)return ;
int xx=pre[id+1][x][y].first,yy=pre[id+1][x][y].second;
output(id-1,xx,yy);
for(int i=0;i<dp[id+1][x][y]-dp[id][xx][yy];i++)printf("%d ",id);
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;i++)scanf("%d",&h[i]),h[i]++;
for(int i=1;i<=n;i++)
for(int j=0;j<=16;j++)
for(int k=0;k<=16;k++)
dp[i][j][k]=INF;
dp[2][h[1]][h[2]]=0;
for(int i=2;i<n;i++)
for(int j=0;j<=h[i-1];j++)
for(int k=0;k<=h[i];k++)
if(dp[i][j][k]!=INF)
{
int mn=(j+b-1)/b;
int mx=max(mn,max((k+a-1)/a,(h[i+1]+b-1)/b));
for(int l=mn;l<=mx;l++)
{
int jj=max(0,k-l*a),kk=max(0,h[i+1]-l*b);
if(dp[i+1][jj][kk]>dp[i][j][k]+l)
{
dp[i+1][jj][kk]=dp[i][j][k]+l;
pre[i+1][jj][kk]=P(j,k);
}
}
}
printf("%d\n",dp[n][0][0]);
output(n-1,0,0);
printf("\n");
return 0;
}