塗色(CQOI2007)

——BZOJ1260_區間dp spa

Description

假設你有一條長度爲5的木版,初始時沒有塗過任何顏色。你但願把它的5個單位長度分別塗上紅、綠、藍、綠、紅色,用一個長度爲5的字符串表示這個目標:RGBGR。 每次你能夠把一段連續的木版塗成一個給定的顏色,後塗的顏色覆蓋先塗的顏色。例如第一次把木版塗成RRRRR,第二次塗成RGGGR,第三次塗成RGBGR,達到目標。 用盡可能少的塗色次數達到目標。code

Input

輸入僅一行,包含一個長度爲n的字符串,即塗色目標。字符串中的每一個字符都是一個大寫字母,不一樣的字母表明不一樣顏色,相同的字母表明相同顏色。ip

Output

僅一行,包含一個數,即最少的塗色次數。字符串

樣例輸入1

AAAAAinput

樣例輸入2

RGBGRstring

樣例輸出1

1it

樣例輸出2

3io

HINT

40%的數據知足:1<=n<=10
100%的數據知足:1<=n<=50class

Analysis

這種題,一個序列,求最小次數,能看出來是區間dp吧。
通常區間dp都是二維,我這裏的i,j表示l,r,[i][j]表示(i,j)這個子序列。dp存答案。
整個區間從什麼狀態轉移過來?
由短到長考慮,考慮長度爲1的區間:dp[i][i]都是1,由於一個格子只用塗一次。
考慮長度爲2的區間:dp[i][i+1],若是i和i+1顏色相同,只用塗一次,若顏色不一樣,就塗兩次。
長度爲3的區間,若1個格子與其餘格子顏色不一樣,那就塗2次,全不一樣塗3次,全相同塗1次。
……
繼續推下去,咱們會發現,長度爲n的區間老是由它的的子區間轉移過來,並且若這個區間的兩端顏色相同,就會少塗一次色。
找到這個規律以後,就能推出方程了。
\[ dp[i][i+j] = min(dp[i][k],dp[k+1][i+j])\]
當區間兩端顏色相同時
\[dp[i][i+j] = dp[i][i+j] - 1\]數據

代碼

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[5005][5005];
char ss[5005];
int n;
int main()
{
    scanf("%s",ss+1);
    n = strlen(ss+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dp[i][j] = inf;
    for(int i=1;i<=n;i++)
        dp[i][i] = 1;
    for(int j=1;j<=n;j++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int k=i;k<=i+j-1;k++)
            {
                dp[i][i+j] = min(dp[i][i+j] , dp[i][k] + dp[k+1][i+j]);
            }
            if(ss[i] == ss[i+j])
                dp[i][i+j]--;
        }
    }
    printf("%d",dp[1][n]);
    return 0;
}
相關文章
相關標籤/搜索