hdu 1358 period 求循环节 KMP

来源:互联网 发布:21端口入侵 编辑:程序博客网 时间:2024/06/06 03:17

主串(被扫描的串):S=‘s0s1...sn-1’,i 为主串下标指针,指示每回合匹配过程中主串的当前被比较字符;

模式串(需要在主串中寻找的串):P=‘p0p1...pm-1’,j 为模式串下标指针,指示每回合匹配过程中模式串的当前被比较字符

 

next数组即模式串第一个对应为-1, 后面的第j个,从j-1个开始往前观察(范围为 (0, j-1] ),看与模式串的第0个开始往后几个想匹配(范围为 [0, j-1)  ),next[j]的值就为多少

例如:

模式串(p1) :a  a  a  a  b  b  a  a

next数组(p2):-1 0  1  2  3  0  0  1

 

在匹配时,如果p1[i] == p2[j] 或者 j==-1( 即模式串串首),则 i++, j++;

如果p1[i] != p2[j],则 j= next[j];

如果 j== len(p2) 则找到,主串中对应的模式串串首位置为 i-strlen(p2)

 

 

 例:

 

#include<cstdio>#include <cstring>#include<iostream>using namespace std;const int maxn= 1000;char s1[maxn], s2[maxn];int next[maxn], n;void getnext(){     //求next数组    memset( next, 0, sizeof( next));    int i=-1, j= 0;    next[0]= -1;    while( j<strlen(s2) -1 ){        if( i== -1 || s2[i]== s2[j]){            i++, j++;            next[j]= i;        }        else i= next[i];    }}int kmp(){    //匹配    int i=0 , j=0 ;    int l1= strlen(s1), l2= strlen(s2);    while( (i<l1) && (j<l2)){        //这里用while(i<strlen(s1) && j<strlen(s2) )不对,        //是我编译器的问题么……可是在循环里输出s1,s2的长度又都是对的        if(j== -1 || s1[i]== s2[j]){            i++, j++;        }        else j= next[j];    }    if( j==l2)        return i-l2;//j== len2时,i的位置对应模式串的最后一位,故主串中的位置为i-len2    else return -1;}int main(){   // freopen("1.txt", "r", stdin);    int i, j;    scanf("%d%s", &n, s1);    while( n-- ){        scanf("%s", s2);        getnext();        printf("%d\n", kmp());    }    return 0;}

 

 

 

hdu 1358 period

http://acm.hdu.edu.cn/showproblem.php?pid=1358

给一字符串,求前缀为周期序列的序列长度,以及循环节

Sample Input
3aaa12aabaabaabaab0


 

Sample Output
Test case #12 23 3Test case #22 26 29 312 4


 

#include <iostream>#include <cstdio>#include  <cstring>using namespace std;const int maxn= 1000010;int n, next[maxn];char ch[maxn];void getnext(){    int i= -1 , j= 0, k;    memset( next, 0, sizeof( next));    next[0]= -1;    while( j< n ){        if( i==-1 || ch[i]== ch[j]){            i++, j++;            next[j]= i;        }        else i= next[i];    }}int main(){ //   freopen("1.txt", "r", stdin);    int i, j, k, text= 1;    while( scanf("%d", &n) && n){        printf("Test case #%d\n", text++);        scanf("%s", ch);        //ch[n]= 'a';       // ch[n+1]= '\0';        getnext();        for( i=2; i<=n; i++){            j= i- next[i];            if( i%j== 0 && i/j>1){                printf("%d %d\n", i, i/j);            }        }        printf("\n");    }    return 0;}