您的位置:首页 > 其它

poj 1159 Palindrome

2011-06-18 18:06 423 查看
/*
Name: poj 1159 Palindrome
Author: Unimen
Date: 16/05/2011 18:55
Description: 最长公共子序列的变形
*/
/*
解题报告:
参照李鑫ppt:
1、对于一个串S=a1a2…an,求最小的m,使得存在一个串S’=b1b2…bm+n满足S为S’的一个子串(可不连续),并且bi=bm+n-i+1(i=1…m+n)。
2、设S ’各个字符中不为S中字符的字符位置集为X 。故
i 属于X 或 m+n-i+1属于X
是不可能同时成立的。所以可以把S中的字符分成两类A,B:
A:S’中与此字符对称的字符出现在S’-S中
B:S’中与此字符对称的字符出现在S中
3、比如把Ab3bd扩充成
d  A  b  3  b  A  d(红色的字母是添加的)
1  2  3  4  5  6   7
位置2,7的对称位置的字符不属于S,
故A={2, 7}
位置3,4,5的对称位置的字符属于S,
故B={3, 4, 5}
4、有以下结论:
|A|+|B|=|S|=n
|A|=|X|
B是回文词且B是S的子串
|X|=|A|=n-|B|,问题转化为求S的最大回文子串B。
注:
一、由于此题数据量较大因此如果dp数组开成int dp[50001][50001]内存会超出限制
解决方法有两个:
1、改为short,尤其是比赛的时候如果没有好的办法,可以优先考虑这种方法
2、用滚动数组存储。滚动数组在做DP的题时经常用到,需注意。下面的代码是用滚动数组做的
二、求回文的时候可以用最长公共子序列解决

*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
short dp[2][5001];  //滚动数组
char szLine[5001];
int n;
int main()
{
int i, j;
while(cin>>n)
{
scanf("%s", szLine+1);
memset(dp, 0, sizeof(dp));
for(i=1; i<=n; ++i)
{
for(j=1; j<=n; ++j)
{
if(szLine[i] == szLine[n-j+1])
{
dp[i%2][j] = dp[(i-1)%2][j-1] + 1;
}
else
{
dp[i%2][j] = _cpp_max(dp[(i-1)%2][j], dp[i%2][j-1]);  //提交时_cpp_max应改为max
}
}
}
cout<<n-dp[n%2]
<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: