Codeforces 6 D. Lizards and Basements 2

問題

n体の敵がいて、それぞれのHPはh[i]である。
魔法を敵iに向けて放つと、敵iにaのダメージを与え、(もし隣がいるなら)隣にもbずつのダメージを与える。


敵1と敵nには直接魔法を放つことはできない。
全ての敵のHPを0より小さくするのに必要な魔法の回数、
およびそのときの対象をどれか1通り出力せよ。

制約条件

3≦n≦10
h[i]≦15

方針

DP+経路復元。


今魔法で狙っている敵+右側3体のHPを覚えておく。すなわち、
dp[i][h1][h2][h3]を、i番目の敵を狙っていて(i-2番目までの敵は全て倒してある)
i-1番目がh1のHPで、i番目がh2のHPで、i+1番目がh3のHPであるような状態における、
魔法の最小詠唱回数とする。

ソースコード

なんか汚い。

int n,a,b,h[15];
int dp[20][20][20][20],prev[20][20][20][20];
void run()
{
	cin>>n>>a>>b;
	rep(i,n)cin>>h[i], h[i]++;
	h[n]=0;
	rep(i,20)rep(j,20)rep(k,20)rep(l,20)dp[i][j][k][l]=inf;
	dp[1][h[0]][h[1]][h[2]]=0;
	for(int i=1;i<n-1;i++)for(int h2=19;h2>=0;h2--)
	for(int h1=19;h1>=0;h1--)for(int h3=19;h3>=0;h3--)if(dp[i][h1][h2][h3]!=inf){
		int nh1=max(0,h1-b), nh2=max(0,h2-a), nh3=max(0,h3-b);
		if(nh1==0){
			if(dp[i+1][nh2][nh3][h[i+2]]>dp[i][h1][h2][h3]+1){
				dp[i+1][nh2][nh3][h[i+2]]=dp[i][h1][h2][h3]+1;
				prev[i+1][nh2][nh3][h[i+2]]=i*20*20*20+h1*20*20+h2*20+h3;
			}
		}
		if(dp[i][nh1][nh2][nh3]>dp[i][h1][h2][h3]+1){
			dp[i][nh1][nh2][nh3]=dp[i][h1][h2][h3]+1;
			prev[i][nh1][nh2][nh3]=i*20*20*20+h1*20*20+h2*20+h3;
		}
		if(h1==0){
			if(dp[i+1][h2][h3][h[i+2]]>dp[i][h1][h2][h3]){
				dp[i+1][h2][h3][h[i+2]]=dp[i][h1][h2][h3];
				prev[i+1][h2][h3][h[i+2]]=prev[i][h1][h2][h3];
			}
		}
	}
	cout<<dp[n-1][0][0][0]<<endl;
	int h1=0,h2=0,h3=0,p=n-1;
	while(h1!=h[0]||h2!=h[1]||h3!=h[2]||p!=1){
		int prv=prev[p][h1][h2][h3];
		int nh1=prv/20/20%20, nh2=prv/20%20, nh3=prv%20, np=prv/20/20/20;
		cout<<np+1<<" ";
		h1=nh1; h2=nh2; h3=nh3; p=np;
	}
	cout<<endl;
}