POJ 1159 Palindrome(字串變回文:LCS)
id=1159
題意:
給你一個字串, 問你做少須要在該字串中插入幾個字元能是的它變成一個迴文串.
分析:
首先把原字串和它的逆串進行匹配, 找出最長公共子序列. 那麼最長公共子序列的字串肯定是一個迴文串. 所以原串剩下的部分是不構成迴文的. 我們僅僅須要加入剩下部分的字元到相應位置, 原串自然就變成了一個迴文.
所以本題的解為: n 減去 (原串與逆串的LCS長度).
令dp[i][j]==x表示串A的前i個字元與串B的前j個字元的子串的最長公共子序列LCS.
初始化: dp全為0.
狀態轉移:
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] ).
終於所求: dp[n][m].
程式實現用的2維滾動陣列, 假設用int[5000][5000]會超記憶體.
AC程式碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5000+5;
int n;
char s1[maxn],s2[maxn];
int dp[2][maxn];
int main()
{
while(scanf("%d",&n)==1)
{
scanf("%s",s1);
for(int i=0;i<n;i++)
s2[i]=s1[n-1-i];
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(s1[i-1]==s2[j-1])
dp[i%2][j]=dp[(i-1)%2][j-1]+1;
else
dp[i%2][j]=max(dp[(i-1)%2][j] , dp[i%2][j-1]);
}
printf("%d\n",n-dp[n%2][n]);
}
return 0;
}