大白书上kmp的例题
这里由于没有对失配函数进一步优化,所以叫mp算法。
先用mp算法 得到字符串t 的每一个t[i]的next数组,其中t[i]的next值应该是 (nextval【i+1】) // 失配函数的写法不同而已,也可以改写成t[i]对应next[i]
-----------------------------------------------以上是KMP算法中的失配函数相关内容------------懂了那个失配函数(网上自己学习)再往下看
以下是证明:
-----------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------
A,B,C,D代表n个不同的数
共4N个数
【1】、从MP算法的失配函数得到 T【i】的next位置为图中下方箭头所指位置 可以确定的是,【0,nex[i]】和【i-next[i],i】是相等的(失配数组的性质),也就是黄色数组的BCD和红色数组的ABC是相等的。
【2】、由于题目要求k大于1,当 i/(i-nex[i]) =2; 即next[i] 为中点; 显然可以分为两段重复的子串,所以k=2。
【3】、当i/(i-next[i])>=2的情况下是否成立呢? 以图为例,可知 i/(i-next[i])=4; 下面我们来看,由【1】得黄色BCD=红色ABC,因为,所以我们可以推知A=B,B=C,C=D,从而A=D; 也就是说,这包含了4个循环节,同理 如果 i/(i-next[i]) = n,那么可以同样地推出 整个串 含有n个循环节。
综上 ,要满足 一个串含有循环节且周期大于1的条件是,i/(i-next[i])==0 (不整除根本凑不了循环节)、 并且由于k>1,所以next[i]!=0,也就是k=1的情况了 。
代码:
-----------------------------------------------------------------------------------------------------------------------------------------------------------
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <cstdio> #include <algorithm> #include <iostream> #include <queue> #include <set> #include <vector> #define inf 0x7fffffff #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 1000005; using namespace std; int nextval[maxn]; char s[maxn]; int max(int a,int b) {return a>b?a:b;} void get_next(char *t,int len) //失配函数 { int i,j; i=1; nextval[1]=0; j=0; while(i<=len) { if (j==0||t[i]==t[j]) { j++; i++; nextval[i]=j; } else j=nextval[j]; } } int main( ) { int n; int cnt=1; while(scanf("%d",&n)!=EOF) { if (!n) break; printf("Test case #%d\n",cnt++); scanf("%s",s+1); memset(nextval,0,sizeof(nextval)); get_next(s,n); int i; for (i=1;i<=n+1;i++) //原next数组存的是失配位的下一位 所以本题要减1 { nextval[i]--; // printf("%d ",nextval[i]); } for (i=1;i<=n;i++) { if ((nextval[i+1])&& ( i%(i-nextval[i+1])==0)) { printf("%d %d\n",i,i/(i-nextval[i+1]));; } } printf("\n"); } return 0; }
另一种写法:
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=0.000001; int val[1000005]; char tm[1000005]; void getnext(char *t,int len) { int i,j; i=1; val[1]=0; j=0; while(i<len) { if (j==0||t[i]==t[j]) { i++;j++;val[i]=j; } else j=val[j]; } } int main() { int cnt=1; int n,i; while(scanf("%d",&n)!=EOF) { if (!n)break; printf("Test case #%d\n",cnt++); scanf("%s",tm+1); getnext(tm,n); for (i=1;i<=n;i++) { if (i%(i-val[i])==0&&tm[val[i]]==tm[i]) if (i/(i-val[i])>1) printf("%d %d\n",i,i/(i-val[i])); } printf("\n"); } return 0; }