Description
有nn个怪物编号~nn,每次可以攻击~n−1n−1中任意一个怪物,第ii个怪物的血量为,一个怪物必须血量为负值才算死亡,但是死亡的怪物依旧可以攻击,如果对第ii个怪物攻击,对第的怪物会造成aa点伤害,对第和第i+1i+1个怪物造成bb点伤害,问最少多少次攻击可以让所有怪物死亡,并输出被攻击怪物的编号
Input
第一行三个整数,之后输入nn个整数(3≤n≤10,1≤b<a≤10,1≤hi≤15)(3≤n≤10,1≤b<a≤10,1≤hi≤15)
Output
输出最少攻击次数和每次攻击的怪物编号
Sample Input
3 2 1
2 2 2
Sample Output
3
2 2 2
Solution
攻击先后次序无关,只需考虑对每只怪物攻击几次即可,故顺序考虑攻击,即如果当前对第ii个怪物攻击,那么要求前个怪物都已经死亡,为避免计算繁琐,把每个怪物的血量加一,这样只要怪物血量清零则死亡,以dp[i][j][k]dp[i][j][k]表示当前攻击第ii个怪物,前个怪物已经死亡,第i−1i−1个怪物血量为jj,第个怪物的血量为kk的条件下需要的最少攻击次数,则有,考虑对第ii个怪物的攻击次数,首先必须让第个怪物死亡才能去攻击第i+1i+1个怪物,所以至少要攻击x=⌈jb⌉x=⌈jb⌉次,最多次数是使得第ii个怪物和第个怪物都死亡,打死第ii个怪物需要攻击次,打死第i+1i+1个怪物需要攻击z=⌈hi+1b⌉z=⌈hi+1b⌉次,那么最多攻击次数即为max(y,z)max(y,z),枚举攻击次数ll,则第个怪物血量变成jj=max(0,k−a∗l)jj=max(0,k−a∗l),第i+1i+1个怪物血量变成kk=max(0,hi+1−b∗l)kk=max(0,hi+1−b∗l),进而有转移:
dp[i+1][jj][kk]=max(dp[i+1][jj][kk],dp[i][j][k]+l)dp[i+1][jj][kk]=max(dp[i+1][jj][kk],dp[i][j][k]+l)
dp[n][0][0]dp[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;
}