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; }