涂色(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;
}
相关文章
相关标签/搜索