——BZOJ1260_区间dp spa
假设你有一条长度为5的木版,初始时没有涂过任何颜色。你但愿把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你能够把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽可能少的涂色次数达到目标。code
输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每一个字符都是一个大写字母,不一样的字母表明不一样颜色,相同的字母表明相同颜色。ip
仅一行,包含一个数,即最少的涂色次数。字符串
AAAAAinput
RGBGRstring
1it
3io
40%的数据知足:1<=n<=10
100%的数据知足:1<=n<=50class
这种题,一个序列,求最小次数,能看出来是区间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; }