1. 程式人生 > >Hdu 3068 Manacher演算法求最長迴文串長度

Hdu 3068 Manacher演算法求最長迴文串長度

最長迴文

Description
給出一個只由小寫英文字元a,b,c…y,z組成的字串S,求S中最長迴文串的長度.
迴文就是正反讀都是一樣的字串,如aba, abba等

Input
輸入有多組case,不超過120組,每組輸入為一行小寫英文字元a,b,c…y,z組成的字串S
兩組case之間由空行隔開(該空行不用處理)
字串長度len <= 110000

Output
每一行一個整數x,對應一組case,表示該組case的字串中所包含的最長迴文長度.

Sample Input
aaaa

abab

Sample Output
4
3

想法:只要理解了Manacher演算法就很簡單了。

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#include <iostream>
using namespace std;
char str[2*110000+10];
int p[10+2*110000];
//因為添加了一倍的特殊字元,所以要乘2.
char s[10+110000];
//原字串。
int len;
void manacher(int len)
{
    str[0]='$';str[1]='#'
; //str[0]是為了不讓陣列越界,至於‘$’和‘#’可以由不與原字串重複的任意特殊字元代替。 for(int i=0;i<len;i++) str[2*(i+1)]=s[i],str[2*(i+1)+1]='#'; //為了排除奇長度與偶長度字串的區別。 str[2*len+2]='\0'; len=2*len+2; int id=0,mx=0; p[0]=0; for(int i=1;i<len;i++) { if(i>=p[id]+id) //超過了以id為中心的最長迴文串的右邊界。
p[i]=1; else p[i]=min(p[2*id-i],mx-i); //如果沒有,請看連結中的圖文解釋(我實在想不出比他更好的了,就不獻醜了)。 while(str[i-p[i]]==str[i+p[i]]) p[i]++; if(p[i]+i>mx) //更新最長迴文串長度。 mx=p[i]+i,id=i; } } int main() { while (~scanf("%s",s)) { len = strlen(s); manacher(len); int ans = 0; for (int i = 0; i<2*len+2; i++) { ans = max(ans,p[i]); } printf("%d\n",ans-1); //減一很重要,可以自己手動舉個例子試試。