UVA 11404 - Palindromic Subsequence LCS

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2399

题目大意:

给定一个由小写字母组成的字符串,删除其中0个或多个字符,使得剩下的字母(顺序不变)组成一个尽量长的回文串。如果有多解,输出字典序最小的解。


思路:

参考别人思路的。。

学到的有:

把一个字符串逆序后和原字符串进最长公共子序列,可以计算出它的最长回文串长度。

这题还要求输出字典序最小的解。

回忆一下LCS过程,如果A[I]==B[j]那么dp[i][j]=dp[i-1][j-1]+1,否则dp[i][j]=max(dp[i-1,j],dp[i][j-1])

这题则需要在dp过程中记录当前串。至于字典序的判断,如果A[I]!=B[j]并且dp[i-1,j]==dp[i][j-1]时,判断(i-1,j)和(i,j-1)记录的字符串哪个字典序小即可。

需要注意的是LCS不一定为回文串。

例如:
kfclbckibbibjccbej
jebccjbibbikcblcfk


bcibbibc是他们的LCS,但是却不是回文串。

但我们可以根据前半段推出后面的。


#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1024;
char s[MAXN],a[MAXN];
int dp[MAXN][MAXN];
string ans[MAXN][MAXN];
int main()
{
	while(~scanf("%s",s+1))
	{
		int L=strlen(s+1);		
		for(int i=0;i<L;i++)
		{
			dp[0][i]=0;
			ans[0][i]="";
		}
		
		for(int i=L,j=1;i>=1;i--,j++)
			a[j]=s[i];
		//这样,问题转化为求s和a的LCS
		for(int i=1;i<=L;i++)
		{
			for(int j=1;j<=L;j++)
			{
				if(a[j]==s[i])
				{
					dp[i][j]=dp[i-1][j-1]+1;
					ans[i][j]=ans[i-1][j-1]+s[i];
				}
				else
				{
					if(dp[i-1][j] > dp[i][j-1])
					{
						dp[i][j]=dp[i-1][j];
						ans[i][j]=ans[i-1][j];
					}
					else if(dp[i-1][j] < dp[i][j-1])
					{
						dp[i][j]=dp[i][j-1];
						ans[i][j]=ans[i][j-1];
					}
					else
					{
						dp[i][j]=dp[i][j-1];
						ans[i][j]=min(ans[i-1][j],ans[i][j-1]);
					}
				}
			}
		}
		string &res=ans[L][L];
		int len=res.size();
		len>>=1;
	//	cout<<res<<endl;
		for(int i=0;i<len;i++)
			cout<<res[i];
		int i;
		if(res.size() &1)	
			i=len;
		else  
			i=len-1;
		for(;i>=0;i--)
			cout<<res[i];
		
		cout<<endl;
	}
}


posted @ 2014-02-13 18:44  hr_whisper  阅读(151)  评论(0编辑  收藏  举报