poj3976
题意:求每个串的最大回文串长度。
这是一份通过manache算法理解过后手动模拟的算法,纯手写,便于理解
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char ch[2000005];
int hui[2000005];
char ca[2000005];
int index=0;
int ma=0;
void solve()
{
//其中p为中心位置,r对应的最右边界,仔细观察可以发现r-p即为p位置的最大回文长度
int p=0,r=0;
int len=strlen(ca);
for(int i=0; i<len; i++)
{
ch[i*2]='#';
ch[i*2+1]=ca[i];
}
ch[len*2]='#';
ch[len*2+1]='\0';
len=2*len+1;
for(int i=0; i<len; i++)
{
if(i>=(r))//当要进行回文求解的i位置在r右边时,无任何优化,暴力匹配。
{
int k=i+1;
int l=0;
while((k<len)&&(2*i-k>=0)&&(ch[k]==ch[2*i-k]))
{
l++;
k++;
}
p=i;
r=l+i;
if(l>ma)
ma=l,index=i;
hui[i]=l;
}
else//反之
{
if((i+hui[2*p-i])<(r))//若通过以p为对称中心i的对称点为2*p-i,若i-i+hui[2*p-i]都在r左边,肯定是匹配的。
{
hui[i]=hui[2*p-i];
}
else//否则要在求解,但有下面的优化
{
//注意这里的批配起始位置为r,起始已匹配成果长度为r-i-1;
int k=r;
int l=r-i-1;
while((k<len)&&(2*i-k>=0)&&(ch[k]==ch[2*i-k]))
l++,k++;
p=i;
r=l+i;
if(l>ma)
ma=l,index=i;
hui[i]=l;
}
}
}
}
int main()
{
int icase=1;
while(cin>>ca)
{
ma=0;
if(strcmp(ca,"END")==0)break;
memset(hui,0,sizeof hui);
solve();
int len=strlen(ch);
cout<<"Case "<<icase++<<": "<<ma<<endl;
}
return 0;
}
再贴一份大神模板
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN=1100100;
char Ma[MAXN*2];
int Mp[MAXN*2];
void Manacher(char s[],int len)
{
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++)
{
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++)
{
Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;//寻找下一个需要判断的地方
while(Ma[i+Mp[i]]==Ma[i-Mp[i]])Mp[i]++;
if(i+Mp[i]>mx)
{
mx=i+Mp[i];
id=i;
}
}
}
char s[MAXN];
int main()
{
int count=0;
while(scanf("%s",s)!=EOF)
{
if(strcmp("END",s)==0)break;
count++;
int len=strlen(s);
Manacher(s,len);
int ans=0;
for(int i=0;i<2*len+2;i++)
{
ans=max(ans,Mp[i]-1);
}
printf("Case %d: ",count);
printf("%d\n",ans);
}
return 0;
}