假设你有一条长度为5的木版,初始时没有涂过任何颜色。你但愿把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。html
每次你能够把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。spa
用尽可能少的涂色次数达到目标。code
输入格式:htm
输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每一个字符都是一个大写字母,不一样的字母表明不一样颜色,相同的字母表明相同颜色。blog
输出格式:字符串
仅一行,包含一个数,即最少的涂色次数。string
很是明显的一道区间DPit
关于区间DP转https://www.cnblogs.com/lizitong/p/10014809.htmlio
咱们要将一个区间涂成给出的颜色。class
这道题的难点在于其与咱们的思惟相逆。
咱们主观上的涂色所有都是先涂底层,而后在逐渐在上面覆盖,而这道题的状态转移方程却不一样。
首先状态,dp[i][j]表示[i]到[j]的最少次数。
注意清初值,因为是求最小,初值清成正无穷,每一个单独的颜色都须要涂,因此清成1。
当咱们枚举长度的时候,若是[i][j]颜色相同,岂不是我在涂[i][j-1]或者[i+1][j]顺带一笔就能够带过去?
这就是我所说的与咱们印象相逆的地方。假设咱们现实中一笔带过去,中间的颜色所有会变色,可是咱们这里是一个逆向的过程,中间的颜色是创建在已经涂过的颜色基础上的。
仔细想一想。
那若是[i][j]颜色不同呢?
那咱们就须要把这段区间分红两段涂,枚举k在区间[i][j]中,把区间分红两段,而后将次数相加。
上代码。欢迎你们在评论区留言讨论。
#include<cstdio> #include<algorithm> #include<cstring> #include<string>
using namespace std; char c[55]; int dp[55][55]; int main() { scanf("%s",c+1); int l = strlen(c+1); memset(dp,0x3f,sizeof(dp)); for(int i = 1;i<=l;i++) { dp[i][i] = 1; } for(int len = 2;len<=l;len++) { for(int i = 1;i+len-1<=l;i++) { int j = i+len-1; if(c[i]==c[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]); } } } } printf("%d",dp[1][l]); return 0; }