區間DP(POJ 1390)

Blocks

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:

1390_1.jpguploading.4e448015.gif轉存失敗重新上傳取消1390_1.jpguploading.4e448015.gif轉存失敗重新上傳取消1390_1.jpguploading.4e448015.gif轉存失敗重新上傳取消
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:

1390_2.jpguploading.4e448015.gif轉存失敗重新上傳取消
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

Source

Liu Rujia@POJ

 題意:給你一個顏色塊序列,每次你可以選擇刪除一些相同顏色且相鄰的方塊,收益是刪除方塊數目的平方,單個方塊也可以刪除,收益爲1,那麼,最大的收益是多少呢

題解:先給出方程dp[l][r][k],l,r代表區間端點,k代表想要和端點r顏色相同的顏色塊的個數

對於給定的方塊,我們先做一下處理,把相同的塊存到一起,消除的時候一塊消除,這樣肯定比單個單個的刪除獲得的收益大,那麼,重點!!!這麼多的塊,怎麼才能讓程序做出最優的消除方案呢?我們這樣想,如果合併以後沒有任何一樣顏色的方塊了,那麼是不就算一下每個合併後方塊的平方和,也就是這樣遞歸計算:calc(l,r-1,0)+(len[r]+k)*(len[r]+k) ;而如果第l個塊和第r個塊顏色一樣,那我們要把他們一起刪除的話,就要把區間[ l+1,r-1 ]的方塊全部刪除掉,而[ l+1,r-1 ]區間內也可能存在和第r塊一樣的顏色塊,那我們在遞歸搜索一下是否存在,若存在,計算進來,沒有的話,直接返回原值,而搜索的話,我們在遞歸的時候枚舉一下也就是   

for(int i=l;i<r;i++)
    {
        if(box[i]==box[r])
            dp[l][r][k] = max( dp[l][r][k] , calc(l,i,len[r]+k)+calc(i+1,r-1,0) );
    }

有點分治的感覺。把上面的情況組合起來就好了!

 

#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <cstring>
#include <algorithm>
#define ll long long
#define mem(vis,x) memset(vis,x,sizeof(vis))
#define TLE std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define test(n) cout<<"Test "<<n<<endl;
#define pb push_back
#define rp(n) for(int i=1;i<=n;i++)
#define rep(n,m) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
const ll mod = 1000000007 ;
const int INF=0x3f3f3f3f;
template<class T> inline T read(){T x=0,w=1;char c=getchar();for(;!isdigit(c);c=getchar())if(c=='-') w=-w;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*w;}
template<class T> inline T read(T&x){return x=read<T>();}
using namespace std;
const int mxn = 1e5+7 ;
ll n,t,m,k,l,r;
/// ll far[mxn] , vis[1600000] , flag[mxn] , dep[mxn] ,dp[mxn][21] , head[mxn] , cnt ,ver[mxn] , lg[mxn] , prime[20202022] ;
/// void getlg(){lg[1] = 0 ; for(int i=2;i<=n+1;i++) lg[i] = lg[i/2]+1;}
/// struct node{int to , nx ;}node[mxn<<1];
int dp[210][210][210],box[mxn],len[mxn] ;
int calc(int l,int r,int k)
{
    if(dp[l][r][k]) return dp[l][r][k] ;
    if(l==r) return (len[r]+k)*(len[r]+k);
    dp[l][r][k] = calc(l,r-1,0)+(len[r]+k)*(len[r]+k);
    for(int i=l;i<r;i++)
    {
        if(box[i]==box[r])
            dp[l][r][k] = max( dp[l][r][k] , calc(l,i,len[r]+k)+calc(i+1,r-1,0) );
    }
    return dp[l][r][k];
}
int main()
{
    int Case = 0 ;
    read(t);
    while(t--)
    {
        read(n);Case++;
        int now = -1 , cnt = 0;
        mem(len,0); mem(dp,0);
        rp(n)
        {
            read(k) ;
            if(k==now) len[cnt]++;
            else box[++cnt] = k , len[cnt]++ , now = k ;
        }
        cout<<"Case "<<Case<<": "<<calc(l,cnt,0)<<endl;
    }
}

石子合併DP題解

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章