POJ1159 Palindrome(最大回文串长度)

 

回文串:给一个串,求最少增添几个字符能使之成为回文串

例如:Ab3bd 首尾增添2d A 

成为Adb3bdA dAb3bAd

解法:动态规划;

1)和杭电多校一题统计回文串的题很像,考虑能不能直接套用;

2)还是先从动态规划的基本元素分析吧;

设状态:dp[i][j]为第i位与第j位之间的串需要多少个最少字符才能组成回文串

3)尝试写状态方程并判断最优子结构性质,无后效性(有向无环):

Dp[i][j] = dp[i-1][j-1];(s[i]=s[j]

Dp[i][j] = dp[i-1][j]+1

发现dp[i][j]代表未配对的字符的值写方程很困难,那就换一个等价的角度,求最长回文串长度,只要拿总长度减去此值就可以了,状态方程大致如下

Dp[i][j] = Maxdp[i-1][j], dp[i][j-1]);

ifs[i]=s[j]

    Dp[i][j] = dp[i-1][j-1] + 2

问题解决!!!

 

另外:求回文串也可看做求原串与其逆串的LCS,用滚动数组优化内存,可限制在几百K内。

 

【源程序1(5000*5000 short型数组)】:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)

short dp[5005][5005];
char s[5005];
int main(){
	//freopen("iofile\\input.txt","r",stdin);
	int n,i,j,d;
	while(~scanf("%d",&n)){
		scanf("%s",s+1);
		
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
		    dp[i][i]=1; 
		for(d=1;d<=n-1;d++){
			for(i=1;i+d<=n;i++){
				j=i+d;
				dp[i][j]=Max(dp[i+1][j],dp[i][j-1]);
				if(s[i]==s[j])
				    dp[i][j]=Max(dp[i][j],dp[i+1][j-1]+2);
			}
		}
		printf("%d\n",n-dp[1][n]);
	}
	return 0;
}

 

【源程序2:LCS+滚动数组】

  别人的代码,拿过来借鉴一下。
 

#include <iostream>
#include <cstdlib>
#include <algorithm>
#define N 5010
#define REP(i,n)	for(i=0;i<n;i++)

using namespace std;

int main()
{
	int i,j,k,n;
	cin>>n;
	char a[N],b[N];
	scanf("%s",a);
	REP(i,n)	b[i] = a[i];
	reverse(a,a+n);
	short dp[2][N];
	REP(i,n)
	{
		dp[0][i] = 0;
		dp[1][i] = 0;
	}
	REP(i,n)
	{
		REP(j,n)
		{
			if( a[i] == b[j] )
				dp[(i+1)%2][j+1] = dp[i%2][j]+1;
			else
			{
				dp[(i+1)%2][j+1] = dp[i%2][j+1];
					if( dp[(i+1)%2][j+1] < dp[(i+1)%2][j] )
						dp[(i+1)%2][j+1] = dp[(i+1)%2][j];
			}
		}
	}
	cout<<n-dp[n%2][n]<<endl;
	return 0;
}


 

posted on 2013-08-13 00:37  Gddxz  阅读(204)  评论(0编辑  收藏  举报

导航