HDU6212 Zuma(區間dp)

Zuma

傳送門1
傳送門2
Think about the Zuma Game. You have a row of at most 200 black(0) or white(1) balls on the table at the start. Each three consecutive balls never share the same colour. You also have infinite amount of black and white balls in your hand. On each turn, you can choose a ball in your hand and insert it into the row, including the leftmost place and the rightmost place. Then, if there is a group of three of more balls in the same colour touching, remove these balls. Keep doing this until no more balls can be removed.
Find the minimal balls you have to insert to remove all the balls on the table.

Input

The first line of input contains an integer T(1T100) which is the total number of test cases.
Each test case contains a line with a non-empty string of 0 and 1 describing the row of balls at the start.

Output

For each test case, output the case number and the minimal balls required to insert in a line.

Sample Input

4
10101
101001001
1001001001
01001101011001100

Sample Output

Case #1: 4
Case #2: 3
Case #3: 3
Case #4: 2


題意

一共有兩種顏色的祖瑪遊戲,每三個連在一起(或者大於三個)的球球就會被消除掉,問將這個字符串消除乾淨的最小吐球個數。

分析

定義dp[ i ][ j ] 表示消除區間從i到j之間的球球的最小吐球個數,再用cnt[ i ] 表示第i個連續相同顏色的球球的個數。
那麼顯然,玩過祖瑪的童鞋們都知道有三種消除一個區間方式(當然你沒玩過也肯定想的出來 ):實際上也可以認爲是兩種
1.將區間分成兩部分,各消除自身的部分:

dp[ i ][ j ]=min(dp[ i ][ j ]dp[ i ][ k ]+dp[k+1][ j ])

2.將中間區間全部消除掉之後,兩端的相同顏色相撞刪除:
dp[ i ][ j ]=min(dp[ i ][ j ]dp[i+1][j1]+(cnt[ i ]+cnt[ j ]3))

3.中間有1個球球,然後消除掉其左右兩側的部分之後,3部分相撞消除:
dp[ i ][ j ]=min(dp[ i ][ j ]dp[i+1][k1]+dp[k+1][j1])
此時要求cnt[ i ]+cnt[ j ]<=3 ,因爲cnt[ i ]cnt[ j ] 都至少是1,如果相加大於3的話,無論先刪除左側區間還是右側區間,都會構成第2種情況。
參考

CODE

#include<cstdio>
#include<cstring>
#define FOR(i,a,b) for(int i=(a),i##_END_=(b);i<=i##_END_;i++)
#define N 205
char s[N];
int cnt[N],dp[N][N];
inline void Min(int &x,int y) {if(x>y)x=y;}
int main() {
    int t;
    int cas=0;
    scanf("%d",&t);
    while(t--) {
        scanf("%s",s);
        int n=strlen(s),m=1;
        cnt[1]=1;
        FOR(i,1,n-1) {
            if(s[i]==s[i-1])cnt[m]=2;
            else cnt[++m]=1;
        }
        FOR(len,0,m)FOR(i,1,m) {
            int j=i+len;
            if(j<=m&&j>=1) {
                if(len==0)dp[i][j]=3-cnt[i];
                else {
                    dp[i][j]=n<<1;
                    FOR(k,i,j-1)Min(dp[i][j],dp[i][k]+dp[k+1][j]);//左邊消左邊的右邊消右邊的
                    if(!(len&1)) {
                        if(cnt[i]+cnt[j]==2)Min(dp[i][j],dp[i+1][j-1]+1);//左右相撞
                        else Min(dp[i][j],dp[i+1][j-1]);
                        if(cnt[i]+cnt[j]<=3)//左中右相撞
                            for(int k=i+2; k<j; k+=2)
                                if(cnt[k]==1)
                                    Min(dp[i][j],dp[i+1][k-1]+dp[k+1][j-1]);
                    }
                }
            }
        }
        printf("Case #%d: %d\n",++cas,dp[1][m]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章