AOJ2221 KULASIS

問題リンク KULASIS

  • 解法

DPです。形はかなり複雑になりました。
あるボタンは0〜3回押す場合を考えれば十分です。4回以上押す場合を考えるのは無駄です。
すると、i段目のボタンについてボタンの押し方は4^4 = 256通りあることになります。
i段目のボタンの押し方とi-1段目のボタンの押し方の組み合わせは256^2 = 65536通りあります。このとき、i-2段目以前についてはi-1段目のボタンの押し方のみに依存するのでこの部分をDPすることになります。つまり、i段目のボタンの押し方をKとしたときの0〜i段目のセルにおける最高得点をdp[i][K]にしまえばいいことになります。
今回のDPは説明がえらいムズイのですが、要は、上から順にボタンの押し方を考えていって、i段目のボタンの押し方に依存しないところは、dp表に値をとっておこうというのが方針です。

  • ソース
import java.util.Scanner;

//KULASIS
public class AOJ2221 {

	int[] f(int x){
		int[] r = new int[4];
		int k = 0;
		while(x>0){
			r[k++] = x%4;
			x/=4;
		}
		return r;
	}

	void run(){
		Scanner sc = new Scanner(System.in);
		int[] p = {0, 60, 70, 80};
		int[][] k = new int[256][];
		for(int i=0;i<256;i++)k[i]=f(i);
		int T = sc.nextInt();
		while(T--!=0){
			int[][] a = new int[5][5];
			for(int i=0;i<5;i++)for(int j=0;j<5;j++)a[i][j]=sc.nextInt()-1;
			int[] dp = new int[256];
			for(int i=0;i<256;i++){
				for(int j=0;j<5;j++){
					int s = a[0][j];
					if(s==-1)continue;
					if(j<4)s+=k[i][j];
					if(j>0)s+=k[i][j-1];
					dp[i] += p[s%4];
				}
			}
			for(int n=1;n<4;n++){
				int[] next = new int[256];
				//n段目の状態
				for(int i=0;i<256;i++){
					int max = 0;
					//n-1段目の状態
					for(int j=0;j<256;j++){
						int sum = 0;
						for(int v=0;v<5;v++){
							if(a[n][v]==-1)continue;
							int s = a[n][v];
							if(v<4)s+=k[i][v]+k[j][v];
							if(v>0)s+=k[i][v-1]+k[j][v-1];
							sum += p[s%4];
						}
						max = Math.max(max, dp[j]+sum);
					}
					next[i] = max;
				}
				dp = next;
			}
			int res = 0;
			for(int i=0;i<256;i++){
				int sum = 0;
				for(int j=0;j<5;j++){
					if(a[4][j]==-1)continue;
					int s = a[4][j];
					if(j<4)s+=k[i][j];
					if(j>0)s+=k[i][j-1];
					sum += p[s%4];
				}
				res = Math.max(res, dp[i]+sum);
			}
			System.out.println(res);
		}
	}

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