动态规划:Codeforces Round #336 (Div. 1)607B.Zuma 区间DP
607B.Zuma
题目大意
就是给你一个数组,每次只能删除里面的回文子串 1 11 121 都算,求删完整串的最少删除次数.我们可以构建区间DP数组dp[i][j],并得出状态转移方程:当s[i]==s[j]时dp[i][j]=dp[i+1][r-1],因为就相当于删里面的回文时顺便删了外面两个对称的,外面两个对称的端点可以和里面的回文再次构成回文,但这里要注意当s[i]==s[j]时,如果区间长度是2,则dp[i][j]=1要特判,如果s[i]!=s[j]时候,我们就相当于把i j 区间割成几块,分别删除回文,最后求和。
状态转移方程:
但这里其实存在错误的地方,我第一次提交的时候错了,错在哪呢?我调试了一下,得出结论。
错在这边,其实对于s[l]==s[r]的dp[l][r],他虽然可以等于dp[l+1][r-1],但是dp[l+1][r-1]并非是最优解,可能把dp[l][r]拆成两块删除的步骤更少,所以不应该加else,对于每种情况都应该加一个切割区间判断最优解。
所以对的状态转移code:
AC代码:
1 //right 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<vector> 6 #include<cstring> 7 #include<string> 8 using namespace std; 9 const int maxn = 5*1e2+5; 10 int gemstone[maxn]; 11 int dp[maxn][maxn]; 12 int read() 13 { 14 int x = 0, f = 1; 15 char ch = getchar(); 16 if (ch > '9' || ch < '0') 17 { 18 f = -1; 19 ch = getchar(); 20 } 21 while (ch >= '0' && ch <= '9') 22 { 23 x = (x << 3) + (x << 1) + ch - '0'; 24 ch = getchar(); 25 } 26 return x * f; 27 } 28 int main() 29 { 30 int n = read(); 31 for (int i = 1; i <= n; ++i) 32 for (int j = 1; j <= n; ++j) 33 dp[i][j] = 0xfffffff;//求最小值,初始化为最大值 34 for (int i = 1; i <= n; ++i)gemstone[i] = read(),dp[i][i]=1; 35 for (int len = 2; len <= n; ++len) 36 { 37 for (int l = 1; l + len - 1 <= n; ++l) 38 { 39 int r = l + len - 1; 40 if (gemstone[l] == gemstone[r]) 41 { 42 if (r - l == 1) 43 dp[l][r] = 1; 44 else 45 dp[l][r] = dp[l + 1][r - 1]; 46 } 47 for (int k = l; k < r; ++k) 48 { 49 dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); 50 } 51 52 } 53 } 54 cout << dp[1][n]; 55 return 0; 56 } 57