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; }
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 ", m/(m-f[m])); } else{ printf("1 "); } } //cout << "Hello world!" << endl; return 0; }
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(" "); } else{ printf(" "); } } } return 0; }
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 ",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] = '