题目大意:求最长回文子串,并输出其中字典序最小的。
思路:转化为LCS。将原来字符串反转,得到str2,然后和原字符串求LCS,求LCS的过程中还需要记录每一个状态所对应的的LCS,因为之后要比较。然后再分两种情况(1)回文串为偶数,那么当str1位置为i时,str2的位置应为len-i。(2)为奇数,那么考虑中间字母为str1[ i ]时,str1的位置为i-1,str2的位置为len-i,这里还需要注意,中间位置要从str[1]开始枚举,因为左、右边可以为空。
很好的题,因为先开始自己想到LCS,但是不会找字典序最小的,原来只要把每个状态d[ i ][ j ] 的s都记录下来就可以了,代码用C++写比较方便,但是对C++不是很熟,代码很多都是照着别人的代码来的。。 = =
代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN = 1111 ;
char str[MAXN];
char str2[MAXN];
struct Node
{
int len;
string s;
bool operator < (const Node & tmp) const
{
if(len == tmp.len)
{
return s>tmp.s;
}
else return len<tmp.len;
}
} d[MAXN][MAXN];
int len;
void LCS()
{
for(int i = 0;i<=len;i++)
{
d[0][i].len = 0;
d[0][i].s.clear();
d[i][0].len = 0;
d[i][0].s.clear();
}
for(int i = 1;i<=len;i++)
{
for(int j = 1;j<=len;j++)
{
if(str[i]==str2[j])
{
d[i][j].len = d[i-1][j-1].len+1;
d[i][j].s = d[i-1][j-1].s + str[i];
}
else
{
d[i][j] = max(d[i-1][j],d[i][j-1]);
}
}
}
}
string roll(string s)
{
string tmp="";
for(int i = s.length()-1;i>=0;i--)
tmp += s[i] ;
return tmp;
}
int main()
{
while(cin>>(str+1))
{
len = strlen(str+1);
for(int i = 1;i<=len;i++)
{
str2[i] = str[len-i+1];
}
LCS();
Node ans;
ans.len = 0;
ans.s.clear();
for(int i = 1;i<len;i++)
ans = max(ans,d[i][len-i]);
ans.len *= 2;
ans.s += roll(ans.s);
Node tmp;
for(int i = 1;i<=len;i++)
{
tmp.len = 2*d[i-1][len-i].len+1;
tmp.s = d[i-1][len-i].s + str[i] + roll(d[i-1][len-i].s);
ans = max(ans,tmp);
}
cout<<ans.s<<endl;
}
return 0;
}