POJ 1390 记忆化搜索

http://poj.org/problem?id=1390

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

题目大意:合并相同颜色的块得到的分数=该块的个数*该块的个数,求合并整个序列所能取得的最大分数。

思路:首先读入序列并把连续的相同颜色的元素合并成一个块,记录其颜色及个数。我们用dp[l][r][len]表示合并区间[l,r]且r右侧还有len个与第r块颜色相同的元素的情况下所能得到的最大分数。那么有两种方式合并:(1)朴素合并:dp[l][r][len]=dp[l][r-1][0]+(cnt[r]+len)*(cnt[r]+len);(2)枚举断点k当color[k]=color[r]时,可以先消去区间[k+1,r-1],再把第k块和第r块一起消掉,dp[l][r][len]=dp[l][k][cnt[r]+len]+dp[k+1][r-1][0]。

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std ;

struct node
{
    int v,cnt;
};

node a[205];
int dp[205][205][205];
int n;

int dfs(int l,int r,int len)
{
    if(l==r)
        return (a[r].cnt+len)*(a[r].cnt+len);
    if(l>r)
        return 0;
    if(dp[l][r][len])
        return dp[l][r][len];
    int temp1=dfs(l,r-1,0)+(a[r].cnt+len)*(a[r].cnt+len);//朴素合并
    int temp2;
    for(int i=l;i<r;i++)
    {
        if(a[i].v==a[r].v)//先消去中间的再把左右颜色相等的一起合并
        {
            temp2=dfs(l,i,a[r].cnt+len)+dfs(i+1,r-1,0);
            if(temp2>temp1)
                temp1=temp2;
        }
    }
    return dp[l][r][len]=temp1;
}

int main()
{
    int t;
    int times=0;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        scanf("%d",&a[1].v);
        a[1].cnt=1;
        int temp;
        int k=1;
        for(int i=1;i<n;i++)
        {
            scanf("%d",&temp);
            if(temp!=a[k].v)
            {
                a[++k].v=temp;
                a[k].cnt=1;
            }
            else
                ++a[k].cnt;
        }
        printf("Case %d: %d\n",++times,dfs(1,k,0));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiji333/article/details/89670680
今日推荐