题目大意:
给出一个字符串(可能有多行),在只考虑字母的情况下(忽略大小写)找出一个最长的回文序列。
思路:
在程序最开始需要对数据进行预处理,提取字符串中的所有字母再全部转换为小写并存入进结构体序列tmp[]中,tmp[i].t表示字符串中第i个字母的小写形式。完成此题目需要动态规划的思想,分成两种情况考虑:
找出最长的奇数回文序列。需要用到一个辅助数组length[]。当tmp[i-length[i]-1].t==tmp[i+1].t时,length[i+1]=length[i]+2。
找出最长的偶数回文序列。同样用到辅助数组length[]。当tmp[i-length[i]].t==tmp[i+1].t时,length[i+1]=length[i]+2。
代码:
/*
ID: lujunda1
LANG: C++
PROG: calfflac
*/
#include
#include
#include
#include
#include
using namespace std;
//words用来存储输入的原始数据
//tmp_words是在处理多行输入时用到的辅助数组
char words[20001],tmp_words[20001];
//计算前需要对原始数据进行处理,仅保留字母(全部转换为小写)并记录每个字母在原始数据中的位置。
struct point
{
char t;
int pos;
}tmp[20001];
//length数组用于记录当前位置所属回文序列的最大长度(实际因回文数列长度的奇偶性而有所差异)
int length[20001];
//多行输入
void input()
{
words[0]='\0';
while(gets(tmp_words))
{
int len=strlen(words);
//如果words长度不为0,则说明现在输入的不是第一行数据。
if(len)
{
//输入前,将“上一行”结尾的‘\0’改为‘\n’。
words[len]='\n';
strcpy(words+len+1,tmp_words);
}
//如果words的长度为0,则说明现在正在输入第一行数据。
else
strcpy(words,tmp_words);
}
}
int main()
{
freopen("calfflac.in","r",stdin);
freopen("calfflac.out","w",stdout);
input();
//len用于记录处理过后的数据的长度。(所有字母的个数)
int len=0;
for(int i=0,tmp_len=strlen(words);i='a'&&words[i]='A'&&words[i]<='Z')
{
tmp[len].pos=i;
tmp[len++].t=words[i]-'A'+'a';
}
//下面代码是找出最大的奇数回文序列。
//max_1表示最大的奇数回文序列长度
//pos_1表示最大的奇数回文序列的最后一个字母所在位置
int max_1=0,pos_1=0;
memset(length,0,sizeof(length));
for(int i=0;i=0&&end<len&&tmp[start].t==tmp[end].t)
//这里需要注意,length[i]表示的是当前“最大奇数回文序列的长度-1”
length[i+1]=length[i]+2;
//不断更新max_1和pos_1的值
if(max_1<length[i])
{
max_1=length[i];
pos_1=i;
}
}
//由length的性质可知,max_1实际是最大长度-1。为了使max_1表示最大长度,这里需要加1。
max_1++;
//下面代码是找出最大偶数回文序列。
//max_2与pos_2的含义与之前类似。
int max_2=0,pos_2=0;
memset(length,0,sizeof(length));
for(int i=0;i=0&&end<len&&tmp[start].t==tmp[end].t)
//这里需要注意,length表示当前“最大偶数回文序列的长度”
length[i+1]=length[i]+2;
if(max_2max_2?max_1:max_2,pos=max_1>max_2?pos=pos_1:pos_2;
printf("%d\n",max);
for(int i=tmp[pos-max+1].pos;i<=tmp[pos].pos;i++)
printf("%c",words[i]);
printf("\n");
}