//目录

Uva 10559 消除方块

题意:

每次可以选择一个区间(连续相同的序列)消除,得分为 len*len;问最大得分。

分析:

很容易想到是区间DP,但是不像普通的区间DP一样切割方式~~~

如果定义 d[ i ][ j ] 区间,那么在里面切割,将有两个部分,而且中间的要连续相等,连续相等的区间可能还要枚举,加上 判断连续相等,可能会时间超,而且不是就算枚举了,剩下的还要合并,确实麻烦。

一种新的区间DP状态定义: d[i][j][k] 区间 i ~ j 后面继续加 k 个字符(与 j 相同)的最优解。

那么答案是: d[1][n][0];

状态转移:首先一种情况是 d[i][j-1][0] + (k+1)^2;

然后是切割方式:如何切割呢?

如果: i 和 r 颜色相同,这里就有可能产生一种切割方式,首先是中间部分 d[i+1][r-1][0] ,然后是合并部分,d[l][i][k+1];

 

新思维,巧妙解决合并的问题~~~

#include <bits/stdc++.h>

using namespace std;

const int maxn = 205;
int n,v[maxn];
int d[maxn][maxn][maxn];

int dp(int l,int r,int k) {
    if(l>r) return 0;
    int& ans = d[l][r][k];
    if(ans) return ans;

    ans = dp(l,r-1,0) + (k+1)*(k+1);

    for(int i=r-1; i>=l; i--) {
        if(v[i]==v[r]) {
            ans = max(ans,dp(l,i,k+1)+dp(i+1,r-1,0));
        }
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);

    for(int z = 1; z<=t; z++) {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) scanf("%d",&v[i]);
        memset(d,0,sizeof(d));

        printf("Case %d: %d\n",z,dp(1,n,0));

    }

    return 0;
}

 

posted @ 2017-09-15 21:59  小草的大树梦  阅读(256)  评论(0编辑  收藏  举报