——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; }