MP and KMP

MP 是 KMP 的简单版本,目前以下题目都是MP算法

KMP的原理就不多说了

http://kb.cnblogs.com/page/176818/

(这个模板起始的next数组值为0,不是-1,在模板中,next数组叫f数组)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn XXX//自己定
char P[maxn] ;
int f[maxn] ;
void getFail ( char *P , int *f )//对子串的处理
{
    int i , j ;
    int m = strlen(P) ;
    f[0] = f[1] = 0 ;
    for( i = 1 ; i < m ; i++ )
    {
        j = f[i] ;
        while( j && P[i] != P[j] )
        {
            j = f[j] ;
        }
        f[i+1] = P[i] == P[j] ? j+1 : 0 ;
    }
}
int find( char *T , char *P , int *f )
{
    int n = strlen( T ) ;
    int m = strlen( P ) ;
    int j , i ;
    getFail( P , f ) ; //预处理匹配串
    for( i = 0 ; i < n ; i++ )
    {
        while( j && P[j] != T[i] )
        {
            j = f[j] ;
        }
        if( P[j] == T[i] ) j++;
        if( j == m ) return i-m;
    }
    return -1 ;//没有匹配到就返回-1
}
基本模板

 

 

题目:

poj3461

/*
匹配串<10,000 被匹配串< 1,000,000 最基本的那种
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define maxnt 1000009
#define maxnw 10009
char w[maxnw];
char t[maxnt];
int f[maxnw];
void getFail(char *p, int *f)
{
    int i,j;
    f[0] = f[1] = 0;
    int m = strlen(p);
    for(i = 1; i<m; i++){
        j = f[i];
        while(j && p[j] != p[i]) j = f[j];
        f[i+1] = p[j]==p[i]? j+1 : 0;
    }
}
int findd()
{
    int ww = strlen(w);
    int tt = strlen(t);
    int j = 0;
    int ans = 0;
    for(int i=0; i<tt; i++)
    {
        while(j && t[i] != w[j]){
            j = f[j];
        }
        if(t[i] == w[j]){
            j++;
        }
        if(j == ww){
            ans++; j = f[j];
        }
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d%*c", &T);
    while( T-- ){
        scanf("%s",w);
        scanf("%s",t);
        getFail(w,f);
        int result = findd();
        cout <<result<< endl;
    }
    return 0;
}
View Code

poj2406

/*
 has huge input, use scanf instead of cin to avoid time limit exceed
 will not exceed 1 million characters
 求一个串的最大循环串,输出循环次数
*/
#define maxn 1001000
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
char str[maxn];
int f[maxn];
void getFail (char *p, int *f)
{
    int j,i;
    int m = strlen(p);
    f[0] = f[1] = 0;
    for(i=1; i<m; i++)
    {
        j = f[i];
        while(j && p[i]!=p[j]){
            j = f[j];
        }
        f[i+1] = p[i]==p[j]? j+1:0;
    }
}
int main()
{
    while(scanf("%s", str ) && str[0]!='.')
    {
        getFail(str,f);
        int m = strlen(str);
        //cout<<m<<""<<f[m]<<endl;
        if( m % (m-f[m]) == 0 ){
            printf("%d\n", m/(m-f[m]));
        }
        else{
            printf("1\n");
        }
    }
    //cout << "Hello world!" << endl;
    return 0;
}
View Code

poj2752

/*
求既是前缀也是后缀的子串长度
1 <= Length of S <= 400000
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define maxn 400009
using namespace std;
char p[maxn];
int f[maxn];
int getans[maxn];
void getFail(char *p, int *f)
{
    int i,j;
    f[0] = f[1] = 0;
    int m = strlen(p);
    for(i = 1; i<m; i++){
        j = f[i];
        while(j && p[j] != p[i]) j = f[j];
        f[i+1] = p[j]==p[i]? j+1 : 0;
    }
}
int Gett(int*getans, char*p)
{
    int countt;
    int last = f[strlen(p)];
    countt = 1;
    getans[0] = strlen(p);
    if(last == 0) {
        return countt;
    }
    else{
        while(last){
            getans[countt++] = last;
            last = f[last];
        }
        return countt;
    }
}
int main()
{
    int countt;
    while(~scanf("%s",p)){
        getFail(p,f);
        countt = Gett(getans, p);
        while(countt){
            printf("%d", getans[--countt]);
            if(countt == 0){
                printf("\n");
            }
            else{
                printf(" ");
            }
        }
    }
    return 0;
}
View Code

poj2185

/**
最小覆盖子串(串尾多一小段时,用前缀覆盖)长度为n-next[n](n-pre[n]),n为串长。
论证见这篇博客:http://blog.csdn.net/fjsd155/article/details/6866991
*/
/*行 <= 10,000 列 <= 75*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#define maxnR 10009
#define maxnC 79
using namespace std;
int r,c;
char sarray[maxnR][maxnC];
char carray[maxnC][maxnR];
int fs[maxnR], f[maxnR];
int gcd(int a_,int b_)
{/*要判断大小*/
    int a,b;
    if(a_>b_){
        a = a_; b = b_;
    }
    else{
        a = b_; b = a_;
    }
    return b==0?a:gcd(b,a%b);
}
int gong(int a,int b)
{
    return a*b/gcd(a,b);
}
void getFail(char *p, int *f)
{
    int i,j;
    f[0] = f[1] = 0;
    int m = strlen(p);
    for(i = 1; i<m; i++){
        j = f[i];
        while(j && p[j] != p[i]) j = f[j];
        f[i+1] = p[j]==p[i]? j+1 : 0;
    }
}
int main()
{
    while(~scanf("%d%d",&r, &c)){
        for(int i=0; i<r; i++){
            scanf("%s",sarray[i]);
            //printf("--%s\n",sarray[i]);
            for(int j=0; j<c;j++){
                carray[j][i] = sarray[i][j];
            }

            getFail(sarray[i], f);
            int n = strlen(sarray[i]);
            fs[i] = n - f[n];
        }
        int hang = 1;
        for(int i=0; i<r; i++){
            hang = gong(hang, fs[i]);
        }
        for(int j=0; j<c; j++){
            carray[j][r] = '\0';
        /*这里出了问题,一开始这句话加在输入行,但是当列比行多,那么我们只保证了r个列串末尾被初始化,不是c个*/
            //printf("--%s\n",carray[j]);
            getFail(carray[j],f);
            int m = strlen(carray[j]);
            fs[j] = m - f[m];
        }
        int lie = 1;
        for(int j=0; j<c; j++){
            lie = gong(lie,fs[j]);
        }
        if(hang > c){
            hang = c;
        }
        if(lie > r){
            lie = r;
        }
        cout << hang*lie << endl;
    }

    return 0;
}
View Code

 

posted @ 2015-03-12 22:23  普洛提亚  阅读(474)  评论(0编辑  收藏  举报