zoukankan      html  css  js  c++  java
  • 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
    ", caseTh, solve_dp(0, cursor, 0));
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    游标本次循环,跳过某些语句
    SQL 把结果集的某列连加成一行
    DotNetty 跨平台的网络通信库(转)
    Slickflow.NET 开源工作流引擎基础介绍-.NET Core2.0 版本实现介绍 (转)
    C# Winform应用程序占用内存较大解决方法整理(转)
    (转)vs2010 vs2013等vs中如何统计整个项目的代码行数
    如何将运维的报警做成运营的报警--Java后端架构
    阿里员工内部常用免费工具包 (转)
    ASP.NET中常用的几个李天平开源公共类LTP.Common,Maticsoft.DBUtility,LtpPageControl (转)
    C#与MATLAB混合编程
  • 原文地址:https://www.cnblogs.com/xinsheng/p/3452710.html
Copyright © 2011-2022 走看看