AOJ2420 Anipero 2012

問題リンク Anipero 2012

  • 解法

DPもといメモ化再帰で解きました。
dp[歌の番号][折っていないサイリウムの本数][折ってから5分経ったサイリウムの本数][折ったばかりのサイリウムの本数] -> 満足度の最大値
という表を埋めます。
サイリウムは折ったとき、振らずにおいておくことができます。i番目の歌の時に折っておいてi+1番目の歌の時にレベル1のサイリウムを振る、なんていう戦略になります。

  • ソース
import java.util.Scanner;

//Anipero 2012
public class AOJ2420 {

	int n, m, MIN = -(1<<29);
	int[] a, b, c;
	int[][][][] dp;
	
	int get(int k, int M, int L1, int L2){
		if(k==n)return 0;
		if(dp[k][M][L1][L2]!=MIN)return dp[k][M][L1][L2];
		int res = c[k] + get(k+1, M, L2, 0);
		for(int d=1;d<=8;d++){
			if(M<d)break;
			res = Math.max(res, c[k] + get(k+1, M-d, L2, d));
		}
		for(int u2=0;u2<=8;u2++){
			if(L2<u2)break;
			for(int u1=0;u1+u2<=8;u1++){
				if(L1<u1)break;
				if(u1==0 && u2==0)continue;
				for(int d=0;d<=8;d++){
					if(M<d)break;
					res = Math.max(res, u2*a[k] + u1*b[k] + get(k+1, M-d, L2, d));
				}
			}
		}
		return dp[k][M][L1][L2] = res;
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt(); m = sc.nextInt();
		a = new int[n]; b = new int[n]; c = new int[n];
		for(int i=0;i<n;i++){
			a[i] = sc.nextInt(); b[i] = sc.nextInt(); c[i] = sc.nextInt();
		}
		dp = new int[n][m+1][m+1][m+1];
		for(int i=0;i<n;i++)for(int j=0;j<=m;j++)for(int k=0;k<=m;k++)for(int l=0;l<=m;l++)dp[i][j][k][l] = MIN;
		int res = MIN+1;
		for(int d=0;d<=8;d++)if(d<=m)res = Math.max(res, get(0, m-d, 0, d));
		System.out.println(res);
	}
	
	public static void main(String[] args) {
		new AOJ2420().run();
	}
}