POJ 1159 Palindrome
Posted tan90丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1159 Palindrome相关的知识,希望对你有一定的参考价值。
题目大意:给定一个长度为n的字符串,求至少添加多少个字符能使得它变成回文串
解题思路:求原串的逆串(abcdd的逆串为ddcba),然后求原串与逆串的最长公共子序列,即为c,则n-c即为最少添加的字符(不懂如何证明,只能大脑大概过明白)
求两个字符串a,b的最长公共子序列:
定义状态dp[i][j]表示a的前i个字符和b的前j个字符的最长公共子序列,那么dp[len1][len2]即为所求结果.
初始状态: dp[i][0] = 0, dp[0][j] = 0, 对所有 i <= len1, j <= len2;
状态转移方程: a[i] == b[j]时, dp[i][j] = dp[i-1][j-1]+1
a[i] != b[j]时, dp[i][j] = MAX(dp[i-1][j], dp[i][j-1]);
更加具体的状态转移方程推导请参考: HDU 1159题解
另外由于此题n可以达到5000,因此开一个dp[5005][5005]的数组会超出内存,
因此需采用一种叫做滚动数组的方式来节省空间。
看状态转移方程,任何dp[i][j]的推导只使用到上一行的数组的状态,
因此实际上开一个dp[2][5005],并把另一个当做当前需要更新的行的上一个状态即可。
滚动数组有两种实现方式:
一是将行进行取模: 如 dp[i%2][j] = dp[(i-1)%2][j]+1; (ai == bi时)
二是定义一个变量e = 0, 每更新一行,就变换e,使e = 1 - e,即dp[e][j] = dp[1-e][j]+1; (ai == bj时)
/* POJ 1159 Palindrome --- dp+滚动数组 */ #include <cstdio> #include <cstring> const int N = 5005; int dp[2][N]; char str1[N], str2[N]; int n; inline int MAX(int a, int b){ return a > b ? a : b; } int main() { #ifdef _LOCAL freopen("D:\\\\input.txt", "r", stdin); #endif int n; //字符串长度为n while (scanf("%d", &n) == 1){ scanf("%s", str1 + 1); //求逆串 for (int i = n; i > 0; --i){ str2[n - i + 1] = str1[i]; } int e = 0; memset(dp, 0, sizeof dp); //dp[i][j]表示子串的最大长度 for (int i = 1; i <= n; ++i){ e = 1 - e; //需要更新的行 即当前行 对应n*n中的 i for (int j = 1; j <= n; ++j){ if (str1[i] == str2[j]){ dp[e][j] = dp[1 - e][j - 1] + 1; //1-e对应i-1 } else{ dp[e][j] = MAX(dp[1 - e][j], dp[e][j - 1]); } } } printf("%d\\n", n - dp[e][n]); } return 0; }
以上是关于POJ 1159 Palindrome的主要内容,如果未能解决你的问题,请参考以下文章