AOJ0234 Aizu Buried Treasure

問題リンク Aizu Buried Treasure

  • 解法

DP+メモ化探索です。
mem[i][j][k]: 段Hにおいて訪れたマスの集合i, 残りの酸素kという状態でマスjに訪れたときの最小コスト
というDPを最下層の段から作って行きます。
H段目のmemを埋めるには1つしたのH+1段目のmemの結果が必要です。ソース中のdp配列には、1段下のmemの結果が入っています。1段ずつ探索しないと、スタックオーバーフローで Runtime Error となるのが関の山なので、このようにしています。
酸素の量の処理でかなりバグを埋め込みやすい問題です。特に酸素残量の初期値が1以下の場合は、必ずNAなので注意が必要です。

  • ソース
import java.util.Scanner;

//Aizu Buried Treasure
public class AOJ0234 {

	int INF = 1<<29;
	int w, h, f, m, o;
	int[][] a;
	int[][][] dp, mem;
	
	int get(int H, int S, int p, int rest){
		if(rest<=1||p<0||w<=p)return INF;
		if(mem[S][p][rest]!=INF)return mem[S][p][rest];
		int res = INF;
		if(p-1>=0){
			int np = p-1, ns = S|(1<<np), nr = rest-1, c = 0;
			if(((S>>np)&1)==0){
				if(a[H][np]>0)nr = Math.min(m, nr+a[H][np]);
				else c+=-a[H][np];
			}
			res = Math.min(res, c+get(H, ns, np, nr));
		}
		if(p+1<w){
			int np = p+1, ns = S|(1<<np), nr = rest-1, c = 0;
			if(((S>>np)&1)==0){
				if(a[H][np]>0)nr = Math.min(m, nr+a[H][np]);
				else c+=-a[H][np];
			}
			res = Math.min(res, c+get(H, ns, np, nr));
		}
		int np = p, ns = 1<<p, nr = rest-1, c = 0;
		if(a[H+1][np]>0)nr = Math.min(m, nr+a[H+1][np]);
		else c+=-a[H+1][np];
		res = Math.min(res, c+dp[ns][p][nr]);
		return mem[S][p][rest] = res;
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		int INF = 1<<29;
		for(;;){
			w = sc.nextInt(); h = sc.nextInt();
			if((w|h)==0)break;
			f = sc.nextInt(); m = sc.nextInt(); o = sc.nextInt();
			a = new int[h][w];
			for(int i=0;i<h;i++)for(int j=0;j<w;j++)a[i][j]=sc.nextInt();
			dp = new int[1<<w][w][m+1];
			for(int i=0;i<1<<w;i++)for(int j=0;j<w;j++)for(int k=0;k<=m;k++)dp[i][j][k]=k==0?INF:0;
			for(int H=h-2;H>=0;H--){
				mem = new int[1<<w][w][m+1];
				for(int i=0;i<1<<w;i++)for(int j=0;j<w;j++)for(int k=0;k<=m;k++)mem[i][j][k]=INF;
				for(int j=0;j<w;j++)for(int k=0;k<=m;k++)get(H, 1<<j, j, k);
				dp = mem;
			}
			int res = INF;
			for(int j=0;j<w;j++)if(o-1>0){
				if(a[0][j]>0)res = Math.min(res, dp[1<<j][j][Math.min(m, o-1+a[0][j])]);
				else res = Math.min(res, -a[0][j]+dp[1<<j][j][o-1]);
			}
			System.out.println(f<res?"NA":res);
		}
	}

	public static void main(String[] args) {
		new AOJ0234().run();
	}
}