ASubsequence is a sequence obtained by deleting zero or more characters in astring. A Palindrome is a string which when read from left to right, reads sameas when read from right to left. Given a string, find the longest palindromicsubsequence. If there are many answers to it, print the one that comes lexicographicallyearliest.
Constraints
• Maximum length of string is 1000.
• Each string has characters `a' to `z' only.
Input
Inputconsists of several strings, each in a separate line. Input is terminated byEOF.
Output
For eachline in the input, print the output in a single line.
Sample Input
aabbaabb
computer
abzla
samhita
Sample Output
aabbaa
c
aba
aha
题目大意:题意是说找一个给定字符串的最大回文子序列,但这个子序列可以不是连续的,对于多种同样长度的回文子串,取字典序最小的。
根据字符串S0的长度可以采用LCS算法,找出字符串S0和其逆字符串S1的最长公共子序列,同时加一个判断就是对于相同长度的公共子串选取字典序最小的。但是还有一种特殊情况,由于LCS过程中是按照字典序排列的,本题要找的是最大回文子串,LCS并不一定能找到回文序列,借用别的例子:
kfclbckibbibjccbej
jebccjbibbikcblcfk
按字典序LCS得到为bcibbibc,并不是回文串,但是可以得到其与最长回文子串的长度应该相等,并且前一半与回文子串相同,因此可以根据前一半回文串得出后一半(主要串长度的奇偶性)。LCS做法代码如下:
#include<bits/stdc++.h>
using namespace std;
string dp[1005][1005];
string s0;
string lcs()
{
string s1(s0.rbegin(),s0.rend());//逆串
int i,j,len;
len=s0.length();
for(i=0; i<1005; i++)
{
dp[0][i]="";
dp[i][0]="";
}
for(i=1; i<=len; i++)
{
for(j=1; j<=len; j++)
{
if(s0[i-1]==s1[j-1])
{
dp[i][j]=dp[i-1][j-1]+s0[i-1];
}
else
{
if(dp[i-1][j].length()==dp[i][j-1].length())//字典序
{
dp[i][j]=min(dp[i-1][j],dp[i][j-1]);
}
else
{
if(dp[i-1][j]<dp[i][j-1])
{
dp[i][j]=dp[i][j-1];
}
else
{
dp[i][j]=dp[i-1][j];
}
}
}
}
}
return dp[len][len];
}
int main()
{
int i,len;
string ans;
while(cin>>s0)
{
ans=lcs();
len=ans.length();
for(i = 0; i < len/2; i++)//输出 注意奇偶
cout << ans[i];
if(len & 1)
{
for(i = len/2; i >= 0; i--)
cout << ans[i];
}
else
{
for(i =len/2-1; i >= 0; i--)
cout << ans[i];
}
cout<<endl;
}
return 0;
}
练习赛时候做做到题不知道怎么想的,觉得LCS算法不行,于是想了个dp的算法,用book[i][j]表示从S[i]到S[j]的最长回文子串的一半,状态转移方程式book[i][j]=max(book[i+1][j],s[i]+book[i+1][k]),k为从j开始向前查找得到的第一个与S[i]相等的字符的位置,但这样做要判断回文串的长度是奇数还是偶数,还要判断字典序,就比较麻烦,不过不会出现LCS的那种奇葩的情况。这个做法代码如下:
#include<bits/stdc++.h>
using namespace std;
struct str
{
string s;
bool flag;//判断回文串长度是奇数还是偶数
};
str s;
str book[1005][1005];
int l;
str dp(int p,int q)
{
if(book[p][q].s!="")
{
return book[p][q];
}
int i,j,k;
str s0,s1,kong,tmp;
kong.flag=0;
kong.s="";
s0.s+=s.s[p];
if(p-q==1)
{
kong.flag=0;
return kong;
}
if(p-q==2)
{
kong.flag=1;
return kong;
}
for(i=q;i>=p;i--)
{
if(s.s[i]==s.s[p])
{
tmp=dp(p+1,i-1);
s0.s+=tmp.s;
s0.flag=tmp.flag;
s1=dp(p+1,q);
if(s0.s.length()<s1.s.length())
{
book[p][q] = s1;
return s1;
}
else
{
if(s0.s.length()>s1.s.length())
{
if(p==i)
s0.flag=1;
book[p][q] = s0;
return s0;
}
else
{
if(s0.flag==1&&s1.flag==0)
{
book[p][q] = s1;
return s1;
}
if(s0.flag==0&&s1.flag==1)
{
if(p==i)
s0.flag=1;
book[p][q] = s0;
return s0;
}
if(s0.s>s1.s)
{
book[p][q] = s1;
return s1;
}
else
{
if(p==i)
s0.flag=1;
book[p][q] = s0;
return s0;
}
}
}
}
}
}
int main()
{
str s0;
s0.flag=0;
int i,j;
while(cin>>s.s)
{
l=s.s.length();
for(i=0;i<l;i++)
{
for(j=i;j<l;j++)
{
book[i][j].s="";
book[i][j].flag=0;
}
}
dp(0,l-1);
s0=book[0][l-1];
cout<<s0.s;
if(s0.flag==1)
{
i=s0.s.length()-2;
}
else
{
i=s0.s.length()-1;
}
for(;i>=0;i--)
{
cout<<s0.s[i];
}
cout<<endl;
}
return 0;
}