KMP专题

POJ 2406 Power Strings

http://poj.org/problem?id=2406

题意:找出s字符窜由多少个重复子窜循环构成

分析:KMP求出next数组,其i-next[i]就是到i为止前面循环节是多少

          那么i/(i-next[i])就是有几个循环节,注意这里的i不是下标,是长度,注意一定要i能够整除(i-next[i])

#include<stdio.h>

#include<string.h>

const int MN=1000010;

int next[MN];

char s[MN];

int len;



void get_next()

{

   next[0]=0;

   next[1]=0;

   for(int i=1;i<len;i++)

   {

       int j=next[i];

       while(j && s[i]!=s[j]) j=next[j];

       next[i+1]=s[i]==s[j]?j+1:0;

   }

}



int main()

{

    int i,j;

    while(scanf("%s",s))

    {

        if(strcmp(s,".")==0) break;

        len=strlen(s);

        get_next();

        if(len%(len-next[len])==0)printf("%d\n",len/(len-next[len]));

        else printf("1\n");

    }

    return 0;

}
View Code

 

POJ 3461 Oulipo

http://poj.org/problem?id=3461

题意:s2包含多少个s1

模板题

#include<stdio.h>

#include<string.h>

const int MN=1000010;



int next[MN];

char s1[MN],s2[MN];



int len;

int ans;



void find(char *T,char *P,int *f)

{

    ans=0;

    int n=strlen(T),m=strlen(P);

    int j=0;

    for(int i=0;i<n;i++)

    {

        while(j && P[j]!=T[i]) j=f[j];

        if(P[j]==T[i]) j++;

        if(j==m) ans++;

    }

}



void get_next()

{

    int len=strlen(s1);

    next[0]=next[1]=0;

    for(int i=1;i<len;i++)

    {

        int j=next[i];

        while(j && s1[i]!=s1[j]) j=next[j];

        next[i+1]=s1[i]==s1[j]?j+1:0;

    }

}





int main()

{

    int i,j;

    int T;

    scanf("%d",&T);

    while(T--)

    {

        scanf("%s",s1);

        scanf("%s",s2);

        get_next();

        find(s2,s1,next);

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 

POJ 2752 Seek the Name, Seek the Fame
http://poj.org/problem?id=2752

题意:找出前缀后缀一样的

分析:回溯next数组就是答案

        我们可以看next[i]=k,表明第i位置的字符的前k个字符和开始的字符相同,此时i位置和k位置的字符不一定相同
        但是i-1和k-1是相同的,当i=len的时候,其len-1就是字符窜的最后一个字符必定和next[len]-1的字符相同的

#include<stdio.h>

#include<string.h>

const int MN= 400010;

char s[MN];

int next[MN];

int num[MN];



void get_next(char *P,int *f)

{

    int m=strlen(P);

    f[0]=f[1]=0;

    for(int i=1;i<m;i++)

    {

        int j=f[i];

        while(j && P[i]!=P[j]) j=f[j];

        f[i+1]=P[i]==P[j]?j+1:0;

    }

}



int main()

{

    int i,j;

    while(scanf("%s",s)!=EOF)

    {

        get_next(s,next);

        int len=strlen(s);

        int cas=0;

        num[cas++]=len;

        for(i=len;;)

        {

            if(next[i]==0) break;

            num[cas++]=next[i];

            i=next[i];



        }

        printf("%d",num[cas-1]);

        for(i=cas-2;i>=0;i--)

           printf(" %d",num[i]);

        printf("\n");

    }

    return 0;

}
View Code

 

POJ  2185 Milking Grid

http://poj.org/problem?id=2185

题意:从一个矩阵中找到小矩阵,该子窜小矩阵,其重复能覆盖成大矩阵

分析:将每一行当作一个判断字符来求行的next,然后再求列的next
        然后再依据循环节的知识先来判断需要几行,然后再需要求第i行的循环节num[i]
        算出最大的子窜长度res,然后判断res%num[i]?=0,若等于0,则说明该最大循环节也是该行的循环节
        这是为了避免如,
        2 2
        ababab
        ccccccc 其结果是4

        数组行列写反了RE到挂.....

#include<stdio.h>

#include<string.h>

const int MR=10010;

const int MC=100;



char s[MR][MC];

int nextC[MR][MC];

int nextR[MR];

int n,m;

int num[MR];



bool judge(int x,int y)

{

    if(strcmp(s[x],s[y])==0) return true;

    return false;

}



void get_NextR()

{

    nextR[0]=nextR[1]=0;

    for(int i=1; i<n; i++)

    {

        int j=nextR[i];

        while(j &&  !judge(i,j)) j=nextR[j];

        nextR[i+1]=judge(i,j)?j+1:0;

    }

}



void get_NextC()

{

    for(int k=0; k<n; k++)

    {

        nextC[k][0]=nextC[k][1]=0;

        for(int i=1; i<m; i++)

        {

            int j=nextC[k][i];

            while(j && s[k][i]!=s[k][j]) j=nextC[k][j];

            nextC[k][i+1]=s[k][i]==s[k][j]?j+1:0;

        }

    }

}



int main()

{

    int i,j;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(i=0; i<n; i++)

            scanf("%s",s[i]);

        get_NextR();

        get_NextC();

        int ans=n-nextR[n];

        int res=0;

        for(i=0; i<ans; i++)//找最大循环节

        {

            num[i]=m-nextC[i][m];

            if(num[i]>res) res=num[i];

        }

        for(i=0; i<ans; i++)

        {

            if(res%num[i]!=0) break;

        }

        printf("%d\n",ans*res);

    }

    return 0;

}
View Code

 

 

你可能感兴趣的:(KMP)