题目描述

假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。
例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽量少的涂色次数达到目标。

输入描述:

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

输出描述:

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

题解

区间dp

显然对于一个区间,只能是由它的子区间再往左涂一次或者再往右涂一次

所以对于一个大于2的区间都可以分成两个子区间来考虑

对于区间l到r

如果s[l]==s[r], 那么涂了l的时候,也一定同时涂上了r

也就是说,转移方程在s[l]==s[r]下为dp[l][r]=min(dp[l+1][r],dp[l][r-1])

如果s[l],s[r]不一样

那么此区间的涂色就可以拆分成两个区间的涂色次数相加

那么我们枚举断点k,此时转移方程为dp[l][r]=min(dp[l][k]+dp[k+1][r],dp[l][r])

代码

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pb push_back
#define pii pair<int,int>
#define all(A) A.begin(), A.end()
#define fi first
#define se second
#define MP make_pair
#define rep(i,n) for(register int i=0;i<(n);++i)
#define repi(i,a,b) for(register int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(register int i=int(b);i>=(a);--i)
template<typename T>
inline T read(){
    T s=0,f=1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f=-1;ch = getchar();}
    while(isdigit(ch)) {s=(s<<3)+(s<<1)+ch-48;ch = getchar();}
    return s*f;
}
#define gn() read<int>()
#define gl() read<ll>()
template<typename T>
inline void print(T x) {
    if(x<0) putchar('-'), x=-x;
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
////////////////////////////////////////////////////////////////////////
const int N=360;
int dp[55][55];
////////////////////////////////////////////////////////////////////////
int main(){
    string s;
    cin>>s;
    int len=s.length();
    s="&"+s;
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=len;++i)dp[i][i]=1;
    for(int l=2;l<=len;++l){
        for(int i=1;i+l-1<=len;++i){
            int j=i+l-1;
            if(s[i]==s[j])dp[i][j]=min(dp[i+1][j],dp[i][j-1]);
            else {
                for(int k=i;k<j;++k){
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
                }
            }
        }
    }
    cout<<dp[1][len]<<endl;
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/