关闭

POJ 3974 最长回文 Manacher算法

519人阅读 评论(0) 收藏 举报

容斥刷不动啊!!今天十分的邪恶加猥琐的注册了一个小号和大一的孩子们一起做题;
也没有要和他们比赛的意思,只是我对算法有很多不熟悉的,所以呢....哎 我的号交几个题,小号交几个题。
做都做了,不管了。
晚上花了一个半小时才看懂的一个算法Manacher,专门用来做回文的....
网上其他的人写得佷详细了,我还是说说自己的吧。
Manacher利用了回文的性质。
假设有一个回文以id为中点,p[id]是这个回文的半径。
那么id右边的点i,若点i在id控制的回文串的范围内。
则i关于id对称的点j,通过几何性质可得出j=id*2-i;
则以j为中点的回文串的左边界若处于id回文串的左边界以内。
则由回文的性质可得知p[i]与p[j]是等价的。
因为以j为中心的字符串完全在id的回文串内,若j所决定的回文串超出了id的左边界.
那么以i为中心的字符串最长为mx-i,也就是i离mx的距离为p[i],i的回文长度。
做完这一步再由i向左右拓展,使得回文串增长。
这样达到的最右边mx进行更新。
大体的算法就是这样了:

#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;

int p[2222222];
char str[1111111],str1[2222222];
int len;

void Init()
{
 	 str1[0]='$';
 	 str1[1]='#';
 	 len=2;
 	 for( int i=0;str[i]!=0;i++ )
 	 {
	  	  str1[len++]=str[i];
	  	  str1[len++]='#';
	 }
	 str1[len]=0;
}

int main()
{
 	int T=0;
 	while( scanf("%s",&str)!=EOF )
 	{
	 	   if( strlen(str)==3 && str[0]=='E' && str[1]=='N' && str[2]=='D' )
	 	   	   break;
 		   //memset( str1,0,sizeof(str1) );
 		   memset( p,0,sizeof(p) );
	 	   Init();
	 	   int id,mx=0;
	 	   for( int i=1;i<len;i++ )
	 	   {
		   		if( mx>i )
		   			p[i]=min(p[(id<<1)-i],mx-i);
		   		else
		   			p[i]=1;
		   		while( str1[i-p[i]]==str1[i+p[i]] )
				   	   p[i]++;
			    if( mx<i+p[i] );
				{
				 	mx=i+p[i];
				 	id=i;
		 		}
	   	   }
	   	   printf( "Case %d: ",++T );
	   	   int ans=0;
	   	   for( int i=1;i<len;i++ )
	   	   		ans=max(p[i],ans);
	   	   printf( "%d\n",ans-1 );
  	}
 	return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场