洛谷 P4170 [CQOI2007]涂色
题目描述
假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。
每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。
用尽量少的涂色次数达到目标。
输入输出格式
输入格式:输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。
输出格式:仅一行,包含一个数,即最少的涂色次数。
输入输出样例
说明
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; }