Hdu_3068 Manacger算法的心得

关于manacher算法,似乎在学完KMP之后,比较容易上手,虽然有些原理方面,我没有理解的太深。

Manacher就是解决回文串的问题,求一个字符串中的最长回文子串。

Manacher算法首先对字符串进行处理:在所有字符之间插入‘#’,这样的好处是,无论最长回文子串是奇数个或者是偶数个,都可以进行处理。

处理过程是这样的

假设原串是这样的

1 2 3 4 5

a b b a d

处理完成一个新数组

0  1  2  3  4  5  6  7  8  9  10  11  12

? #  a #  b  #  b  #  a  #  d    #   0

    1  2  1  2  5  2  1  2  1   2    1

首尾设置完全不相干的字符,是为了检测回文时,不会被算进去。

最下一列叫做P[i] ,用来记录当前位的回文个数,如果前后都不回文,默认p[i]=1,(可以当成自身回文)。

算法核心部分有三部分

还是直接用代码来讲吧:

HD#include <iostream>

#include <cstdio>
#include <cstring>
#define maxn 1100050
char str[maxn];
char a[maxn<<1];
int p[maxn<<1];
int min(int x,int y)
{
    if (x<y) return x;
    return y;
}
int main()
{while (scanf("%s",&str[1]))
    {

      if (str[1]=='E') break;
        int i,j;
        a[0]='?',a[1]='#';
        for (i=1; str[i]; i++)//处理成新的字符串。
        {
            a[(i<<1)]=str[i];
            a[(i<<1)+1]='#';
        }
        int n=(i<<1);
        a[n]=0;
        int maxid=0,maxl=0,id=0;
        for (i=1; i<n; i++)//代码的核心部分。
        {
            if (maxid>i)//如果之前记录的最大回文覆盖超过了当前点坐标,进行比较(这一步其实我也不是很理解,只知道可以节省搜索,优化时间)
                p[i]=min(p[2*id-i],maxid-i); //进行覆盖度的比较,取较小的为p[i]
            else
                p[i]=1;  //否则直接定义为默认值1。
            while (a[i+p[i]]==a[i-p[i]]) p[i]++; //前后搜索,若回文,则+1;
            ifmaxid)//获取当前最大覆盖面,和覆盖点。
            {
                maxid=p[i]+i;   
                id=i;
            }
            if (p[i]>maxl) maxl=p[i]; //最大回文长度保存在p[i]中,取p[i]最大值即可。(此时最长回文串的中间点即为i点(不过是加了‘#’的新串))
        }
        printf("%d\n",maxl-1);
    }
    return 0;
}

posted @ 2013-08-06 13:33  KRisen  阅读(255)  评论(0编辑  收藏  举报