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