您的位置:首页 > 其它

poj 1961 Period(KMP, 最短循环节)

2012-10-27 08:24 441 查看
题目链接:

POJ : http://poj.org/problem?id=1961

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

ZOJ : http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2177

题目大意:

给定一个长度为n的字符串s,求它的每个前缀的最短循环节。换句话说,对于每个i(2<=i<=n),求一个最大的整数K>1(如果K存在),使得S的前i个字符组成的前缀是某个字符串重复K次得到的。输出所有存在K的i和对应的K。

比如对于字符串aabaabaabaab, 只有当i=2,6,9,12时K存在,且分别为2,2,3,4

分析与总结:

很经典的一道题目, 各大OJ都有收录。

开始做这题的时候,刚刚看懂KMP,没看最短循环节的相关资料,自己乱搞,花了两节离散数学课想,结果终于AC了 = =, 但不幸的是,结果发现只是再HDU和ZOJ过了,而poj的还是WA 。。。

然后学习《算法入门经典-训练指南》上面的方法,在poj上才成功AC。

虽然没能在poj上成功AC,但是经过这题的思考,对KMP的失配函数获取next的过程和原理有了更深的理解和体会。

代码:



1. 自己乱搞的代码, poj无法AC,求破

#include<cstdio>
#include<cstring>
const int MAXN = 1000005;

char T[MAXN];
int  f[MAXN];
int n;

void getFail(char *P, int *f){
    f[0]=f[1]=0;
    int start=1;
    int n=strlen(P);
    bool flag=true; 

    for(int i=1; i<n; ++i){
        int j=f[i];
        while(j && P[i]!=P[j]){
            flag=false;
            j=f[j];
        }
        if(P[i]==P[j]){
            f[i+1]=j+1;
            if(f[i+1]==1){
                flag=true;
                start=i;
            }
            if(flag && (i+1)>=start*2 && (i+1)%start==0){
                printf("%d %d\n",i+1,(i+1)/start);
            }
        }
        else{
            flag=true;
            start=i+1;
            f[i+1]=0;
        }
    }
}

int main(){
    int cas=1;
    char ch;
    while(~scanf("%d%*c",&n) && n){
        printf("Test case #%d\n",cas++);
        gets(T);
        getFail(T,f);
        puts("");
    }
    return 0;
}


2. 从刘汝佳的大白书(算法入门经典-训练指南)学来的方法。

#include<cstdio>
#include<cstring>
const int MAXN = 1000005;

char T[MAXN];
int  f[MAXN];
int n;

void getFail(char *P, int *f){
    f[0]=f[1]=0;
    int start=1;
    int n=strlen(P);
    for(int i=1; i<n; ++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 cas=1;
    char ch;
    while(~scanf("%d%*c",&n) && n){
        printf("Test case #%d\n",cas++);
        gets(T);
        getFail(T,f);
        for(int i=2; i<=n; ++i){
            if(f[i]>0 && i%(i-f[i])==0){
                printf("%d %d\n",i,i/(i-f[i]));
            }
        }
        puts("");
    }
    return 0;
}




—— 生命的意义,在于赋予它意义士。


原创 http://blog.csdn.net/shuangde800 , By
D_Double (转载请标明)


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: