标签:
UVa 10739 String to Palindrome(经典回文串区间DP)
题意:
给定一个字符串,可以对其进行删除,插入,替换操作。
问最少经过几次操作,可以使这个字符串变成回文字符串。
思路:
看得别人的 题解,最优化问题,用较为直接的方法处理时发现情况很复杂,很多时候就要考虑动态规划了。先从整体出发,由大到小,看往少一个两个元素的情况进行最优递归,如何得到结果。
(这里区间DP即是不断向两侧扩大规模)
(1)如果最外层两个字符相同,s[0]==s[n],那么这两个字符外侧肯定不用考虑了,只要内部最优即可。
dp[0][n]=dp[0+1][n-1];
(2)如果最外层两个字符不相同,s[0]!=s[n],这时必须要进行操作。考虑其子回文串有左回文[0,n-1],右回文[1,n],和中间回文[1,n-1]三个,当子回文串最优后,只需进行一次操作即可。对于子子回文这不用考虑了,因为它必然要转移到这三个子回文中的一个,花费>=子回文,不考虑。只要其转移代价最优时,子回文最优,结果也就最优了(dp基本思想,还没弄熟)。
增删操作对左右回文可行,那么dp[0][n]=min(dp[1][n]+1,dp[0][n-1]+1),而改操作对三种情况都可行dp[0][n]=min(dp[1][n]+1,dp[0][n-1]+1,dp[1][n-1]+1);把 0,n换成i,j;
综上 dp[i][j]=min(min(dp[i + 1][j], dp[i][j - 1]) + 1,dp[i + 1][j - 1] + 1);
#define _CRT_SECURE_NO_DEPRECATE #include<cstdio> #include<cmath> #include<cstring> #include<ctype.h> #include<iostream> #include<algorithm> #include<vector> using namespace std; #include <cstdio> #include <cstdlib> #include <cstring> const int MAXN = 1010; char str[MAXN]; int dp[MAXN][MAXN]; int main() { int cases, cc = 0; scanf("%d", &cases); while (cases--) { scanf("%s", str); int n = strlen(str); for (int i = 0; i < n; ++i) { dp[i][i] = 0; if (str[i] == str[i + 1]) dp[i][i + 1] = 0; else dp[i][i + 1] = 1; } for (int p = 2; p < n; ++p) { for (int i = 0, j = p; j < n; ++i, ++j) { if (str[i] == str[j]) dp[i][j] = dp[i + 1][j - 1]; else dp[i][j] =min(min(dp[i + 1][j], dp[i][j - 1]) + 1,dp[i + 1][j - 1] + 1); } } printf("Case %d: %d\n", ++cc, dp[0][n - 1]); } return 0; }
来源:http://www.cnblogs.com/kedebug/archive/2012/11/19/2777249.html
标签:
原文地址:http://www.cnblogs.com/lgc2583657917/p/4417475.html