码迷,mamicode.com
首页 > 编程语言 > 详细

初涉后缀数组

时间:2014-10-10 17:59:34      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:style   io   os   for   sp   on   cti   amp   ef   

以POJ 1743为例。模板中的基数排序基于前向星。

具体证明过程详见 算法合集之《后缀数组——处理字符串的有力工具》,很不错的一篇论文。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <ctime>
#include <iomanip>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-6)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 1000000007

using namespace std;

const int MAXN = 20510;

int s[MAXN];

int Rank[2*MAXN],sa[2*MAXN],tr[2*MAXN],high[MAXN];

struct N
{
    int v,next;
}edge[2*MAXN];

int tail[MAXN],Top;

inline void Link(int u,int v)
{
    edge[Top].v = v;
    edge[Top].next = -1;
    edge[tail[u]].next = Top;
    tail[u] = Top++;
}

void Get_SA(int *s,int n)
{
    memset(Rank,0,sizeof(Rank));
    memset(sa,0,sizeof(sa));

    int i,j,k,ans,site;

    for(i = max(n,200);i >= 0; --i)
        tail[i] = i,edge[i].next = -1;

    Top = max(n,200)+1;

    for(i = 1; i <= n; ++i)
        Link(s[i],i);

    ans = 1,site = 1;

    for(i = 0; i <= 200; ++i)
    {
        for(j = edge[i].next; j != -1; j = edge[j].next)
            sa[site++] = edge[j].v,Rank[edge[j].v] = ans;
        if(edge[i].next != -1)
            ans++;
        tail[i] = i,edge[i].next = -1;
    }

    for(k = 1;k <= n; k <<= 1)
    {
        Top = n+1;
        for(i = 1;i <= n; ++i)
            Link(Rank[sa[i]+k],sa[i]);

        site = 1;

        for(i = 0;i <= n; ++i)
        {
            for(j = edge[i].next;j != -1; j = edge[j].next)
                sa[site++] = edge[j].v;
            tail[i] = i,edge[i].next = -1;
        }

        Top = n+1;

        for(i = 1;i <= n; ++i)
            Link(Rank[sa[i]],sa[i]);

        site = 1;

        for(i = 1;i <= n; ++i)
        {
            for(j = edge[i].next;j != -1; j = edge[j].next)
                sa[site++] = edge[j].v;
            tail[i] = i,edge[i].next = -1;
        }

        for(tr[sa[1]] = 1,i = 2,ans = 1;i <= n; ++i)
        {
            if(Rank[sa[i]] != Rank[sa[i-1]] || Rank[sa[i]+k] != Rank[sa[i-1]+k])
                ans++;
            tr[sa[i]] = ans;
        }

        for(i = 1;i <= n; ++i)
            Rank[i] = tr[i];
        if(ans >= n)
            break;
    }

    for(i = 1,k = 1;i <= n; ++i)
    {
        if(k) k--;
        if(Rank[i] == 1) {k = 0;high[1] = n-sa[1]+1;continue;}
        j = sa[Rank[i]-1];
        while(i+k <= n && j+k <= n && s[i+k] == s[j+k])
            k++;
        high[Rank[i]] = k;
    }
//
//    for(i = 1;i <= n; ++i)
//        printf("i = %2d SA = %2d Rank = %2d high = %2d\n",i,sa[i],Rank[i],high[i]);

    //以上为Rank,SA,HIGH的构造过程
}

bool Check(int mid,int n)
{
    int L = sa[1],R = sa[1],i;

    for(i = 2;i <= n; ++i)
    {
        if(high[i] >= mid)
        {
            L = min(sa[i],L),R = max(sa[i],R);
            if(L+mid < R)
                return true;
        }
        else
        L = sa[i],R = sa[i];
    }
    return false;
}

int main()
{
    int i,n;

    while(scanf("%d",&n) && n)
    {
        for(i = 1;i <= n; ++i)
            scanf("%d",&s[i]);

        for(i = n;i >= 2; --i)
            s[i] -= s[i-1]-100;

        Get_SA(s,n);

        int mid,anw = 0,Low = 1,High = n;

        while(Low <= High)
        {
            mid = (Low + High)>>1;

            if(Check(mid,n))
                anw = max(anw,mid),Low = mid+1;
            else
                High = mid-1;
        }

        printf("%d\n",anw+1 < 5 ? 0 : anw+1);
    }
    return 0;
}






初涉后缀数组

标签:style   io   os   for   sp   on   cti   amp   ef   

原文地址:http://blog.csdn.net/zmx354/article/details/39964767

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!