POJ 1390 Blocks (区间DP)

Description

Some of you may have played a game called 'Blocks'. There are n blocks in a row, each box has a color. Here is an example: Gold, Silver, Silver, Silver, Silver, Bronze, Bronze, Bronze, Gold. 
The corresponding picture will be as shown below: 
 
Figure 1

If some adjacent boxes are all of the same color, and both the box to its left(if it exists) and its right(if it exists) are of some other color, we call it a 'box segment'. There are 4 box segments. That is: gold, silver, bronze, gold. There are 1, 4, 3, 1 box(es) in the segments respectively. 

Every time, you can click a box, then the whole segment containing that box DISAPPEARS. If that segment is composed of k boxes, you will get k*k points. for example, if you click on a silver box, the silver segment disappears, you got 4*4=16 points. 

Now let's look at the picture below: 
 
Figure 2


The first one is OPTIMAL. 

Find the highest score you can get, given an initial state of this game. 

Input

The first line contains the number of tests t(1<=t<=15). Each case contains two lines. The first line contains an integer n(1<=n<=200), the number of boxes. The second line contains n integers, representing the colors of each box. The integers are in the range 1~n.

Output

For each test case, print the case number and the highest possible score.

Sample Input

2

9

1 2 2 2 2 3 3 3 1

1

1

Sample Output

Case 1: 29

Case 2: 1

 

思路:

1. 将颜色相同又邻接的方块合并到一起, 成为一个 segment. 由得分的规则知, 一个 segment 同时消除一定比 segment 内部分成几个部分再消除得分高

2. 设 i 表示 segment 的 index. 那么 color[i], len[i] 分别代表第 i 个 segment 的颜色和长度

3. dp[i, j, k] 表示从第 i 到 第 j 个 segment, 并且第 j 个 segment 后面还有 k 个不与 j 相邻但颜色与 j 相同的方块数

4. 当第 j 个 segment 与后面 k 个结合时, 那dp[i, j, k] = dp[i, j-1, 0] + (len[j]+k)^2

5. 当第 j 个 segment 与前面的某段合并时, dp[i, j, k] = max(dp[i, j, k], dp[i, s, k+len[j]]+dp[s+1, j-1, 0])

 相当于先消除 [s+1, j-1] 这些方块

6. 由 (5) 的状态转移方程可以看出, 有 max, 有枚举, 这是一个典型的记忆化搜索过程

 

update 2014年3月15日15:31:20

1.思考时应当考虑从后向前推

 

 

代码: 

#include <iostream>

using namespace std;



const int MAXN = 210;

int testCase, N;

int color[MAXN];

int len[MAXN];

int block[MAXN];

int dp[MAXN][MAXN][MAXN];



int solve_dp(int l, int r, int k) {

	if(dp[l][r][k]) 

		return dp[l][r][k];

	if(l == r)

		return dp[l][r][k] =(k+len[r])*(k+len[r]);

	// 直接消除

	//cout << solve_dp(l, r-1, 0) + (k+len[r])*(k+len[r]) << endl;

	dp[l][r][k] = solve_dp(l, r-1, 0) + (k+len[r])*(k+len[r]);

	// 先消除中间的, 合并 color[r], 在消除颜色为 r 的

	for(int i = l; i < r; i++) {

		if(color[i] == color[r])

			dp[l][r][k] = max(dp[l][r][k], solve_dp(l, i, k+len[r]) + solve_dp(i+1, r-1, 0)); 

	}

	return dp[l][r][k];

}

int main() {

	freopen("E:\\Copy\\test\\in.txt", "r", stdin);

	cin >> testCase;

	int caseTh = 0;

	while(testCase--) {

		caseTh++;

		cin >> N;

		for(int i = 0; i < N ; i ++) {

			cin >> block[i];

		}

		color[0] = block[0];

		len[0] = 1;

		int cursor = 0;

		for(int i = 1; i < N; i ++) {

			if(block[i] == block[i-1]) {

				len[cursor]++;

			}else{

				cursor ++;

				color[cursor] = block[i];

				len[cursor] = 1;

			}

		}

		memset(dp, 0, sizeof(dp));

		printf("Case %d: %d\n", caseTh, solve_dp(0, cursor, 0));

	}

	return 0;

}

  

你可能感兴趣的:(block)