[BZOJ 1260][CQOI2007]塗色paint 題解(區間DP)

[BZOJ 1260][CQOI2007]塗色paint

Description

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

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

Output
僅一行,包含一個數,即最少的塗色次數。spa

Solution

1.首先咱們先把數列收縮一下:由於一段連續的同色只需被刷一次,而後對應位置的表置爲1;code

2.考慮DP。htm

  • 當枚舉的區間【L,R】左右端點顏色相同時,只需讓第一次刷左或右端點時多刷一個格子便可,因此
if(list[l]==list[r])f[l][r]=min(f[l][r-1],f[l+1][r]);
  • 當枚舉區間兩側顏色不一樣時,直接枚舉斷點鬆弛大的區間便可。

Code

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

string s;
bool use[27];
int num[27],list[110],f[110][110];

int main(){
    cin>>s;
    memset(f,0x3f,sizeof(f));
    for(int i=0;i<s.size();++i){
        while(s[i]==s[i+1])++i;
        if(use[s[i]-'A'+1])list[++list[0]]=num[s[i]-'A'+1];
        else{
            use[s[i]-'A'+1]=1;
            num[s[i]-'A'+1]=++num[0];
            list[++list[0]]=num[0];
        }
        f[list[0]][list[0]]=1;
    }
    for(int len=2;len<=list[0];++len)
        for(int l=1;l<=list[0]-len+1;++l){
            int r=l+len-1;
            if(list[l]==list[r])f[l][r]=min(f[l][r-1],f[l+1][r]);
            else for(int k=l;k<r;++k)
                    f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
        }
    printf("%d",f[1][list[0]]);
    return 0;
}

有關區間DP的其餘講解參考個人隨筆:http://www.cnblogs.com/COLIN-LIGHTNING/p/9038198.htmlblog

相關文章
相關標籤/搜索