洛谷 P4170 [CQOI2007]涂色

题目描述

假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。

每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。

用尽量少的涂色次数达到目标。

输入输出格式

输入格式:

输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。

输出格式:

仅一行,包含一个数,即最少的涂色次数。

输入输出样例

输入样例#1: 复制
AAAAA
输出样例#1: 复制
1
输入样例#2: 复制
RGBGR
输出样例#2: 复制
3

说明

40%的数据满足:1<=n<=10

100%的数据满足:1<=n<=50

 

 

题解:

  这个题目,我们可以发现,每次如果出现重复的字母在一起那么他们涂改的次数是一样的,如HHR和HR,都只需要2次,所以我们可以将字符串先unique。

  我们设dp[i][j]表示将i~j涂改合法的最小次数,那么区间套路的转移dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]),然后一个转移通过样例就可以想到,如果i和j的颜色相同,我们可以,先一次涂完i和j,然后将i~j之间涂成最优dp[i][j]=min(dp[i][j],dp[i+1][j-1]+1),但发现还是wa的,如FRFUTAUF。

  所以发现如果i,j相同,就可以修改之前的操作,可以一开始,就把i和j涂道,dp[i][j]=min(dp[i][j],min(dp[i+1][j],dp[i][j-1]));

 

代码:

  

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 55
#define ll long long
using namespace std;
ll dp[MAXN][MAXN];
char a[MAXN];

int main()
{
    scanf("%s",a+1);
    int len=strlen(a+1);
    len=unique(a+1,a+len+1)-a-1;
    memset(dp,37,sizeof(dp));
    for(int i=1;i<=len;i++) dp[i][i]=1;
    for(int lenn=2;lenn<=len;lenn++){
        for(int i=1;i<=len;i++){
            int j=i+lenn-1;if(j>len) continue;
            for(int k=i;k<=j;k++)
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
            if(a[i]==a[j]) dp[i][j]=min(dp[i][j],dp[i+1][j-1]+1),dp[i][j]=min(dp[i][j],min(dp[i+1][j],dp[i][j-1]));
        }
    }
    printf("%lld",dp[1][len]);
    return 0;
}

 

posted @ 2018-08-15 19:02  人间失格—太宰治  阅读(210)  评论(0编辑  收藏  举报