Poj--2406(KMP,周期)

2014-12-12 23:55:35

思路:时隔半年,终于通过Matrix67的文章搞懂KMP了,orz。。。

  这题加深了我对KMP本质的了解,题目让你求的是最长周期串的长度。

  仔细考虑,我们发现get_P过程(就是另一种写法里的get_next),就是一种自我匹配找周期的过程!

  【观察abcabcabc,P[9]=6,P[6]=3,P[3]=0,而且s[9]=s[6]=s[3],再者P[9]是从P[8]转移来的,换句话说是从P[6]转移过来的,P[6]=3说明包含s[6]在内的3个字符(s[3]->s[6])与头3个字符相等,而P[6]=6说明包含s[9]在内的6个字符(s[3]->s[9])与头6个字符相等。思考:P[6]说明abc这个周期重复2次,而P[9]说明abc这个周期重复了3次!

  所以P可以理解为最大周期包含串长度(自己YY的玩意),abcabcabc的P[9]=6可以理解为前(9-6=3)个字符为周期,然后P[9]=6意思是以s[9]为终点的串包含了6个字符(也就是两个周期),我们命名这个串为周期包含串;再来个更普通的例子:abcabcab,P[8]=5,理解为前(8-5=3)个字符为周期,然后P[8]=5的意思是以s[8]为终点的周期包含串包含了5个字符,我们发现5个字符不是完整的两个周期,没错,差一个字符,回过去观察,的确差一个c才能形成两个周期。也就是说P[8]=5包含着以s[8]为终点的周期包含串正在形成第二个周期,但还没完成。

  最后一个例子:abcbcabc,P[8]=3,理解为以s[8]为终点的周期包含串已经有了3个字符,但我们来看看周期是什么:8 - 3 = 5,也就是s[1]->s[5] : abcbc,显然P[8]还没包含一整个周期。以上解释纯属个人看完Matrix67文章后对本题的些许理解,望纠正与交流。】

 1 /*************************************************************************
 2     > File Name: 2406.cpp
 3     > Author: Natureal
 4     > Mail: 564374850@qq.com 
 5     > Created Time: Fri 12 Dec 2014 10:30:00 PM CST
 6 ************************************************************************/
 7 
 8 #include <cstdio>
 9 #include <cstring>
10 #include <cstdlib>
11 #include <cmath>
12 #include <vector>
13 #include <map>
14 #include <set>
15 #include <stack>
16 #include <queue>
17 #include <iostream>
18 #include <algorithm>
19 using namespace std;
20 #define lp (p << 1)
21 #define rp (p << 1|1)
22 #define getmid(l,r) (l + (r - l) / 2)
23 #define MP(a,b) make_pair(a,b)
24 typedef long long ll;
25 typedef unsigned long long ull;
26 const int INF = 1 << 30;
27 const int maxn = 1e6 + 10;
28 
29 char s[maxn];
30 int P[maxn];
31 int len;
32 
33 void Get_P(){
34     P[1] = 0;
35     int j = 0;
36     for(int i = 2; i <= len; ++i){
37         while(j > 0 && s[j + 1] != s[i]) j = P[j];
38         if(s[j + 1] == s[i]) j++;
39         P[i] = j;
40     }
41 }
42 
43 int main(){
44     while(scanf("%s",s + 1) != EOF){
45         if(s[1] == '.')
46             break;
47         len = strlen(s + 1);
48         Get_P();
49         if(len % (len - P[len]) == 0) printf("%d\n",len / (len - P[len]));
50         else printf("1\n");
51     }
52     return 0;
53 }

 然后为了适应字符串index一般从0开始,写了一个从0开始的版本:

 1 /*************************************************************************
 2     > File Name: 2406.cpp
 3     > Author: Natureal
 4     > Mail: 564374850@qq.com 
 5     > Created Time: Fri 12 Dec 2014 10:30:00 PM CST
 6 ************************************************************************/
 7 
 8 #include <cstdio>
 9 #include <cstring>
10 #include <cstdlib>
11 #include <cmath>
12 #include <vector>
13 #include <map>
14 #include <set>
15 #include <stack>
16 #include <queue>
17 #include <iostream>
18 #include <algorithm>
19 using namespace std;
20 #define lp (p << 1)
21 #define rp (p << 1|1)
22 #define getmid(l,r) (l + (r - l) / 2)
23 #define MP(a,b) make_pair(a,b)
24 typedef long long ll;
25 typedef unsigned long long ull;
26 const int INF = 1 << 30;
27 const int maxn = 1e6 + 10;
28 
29 char s[maxn];
30 int P[maxn];
31 int len;
32 
33 void Get_P(){
34     P[0] = -1;
35     int j = -1;
36     for(int i = 1; i < len; ++i){
37         while(j >= 0 && s[j + 1] != s[i]) j = P[j];
38         if(s[j + 1] == s[i]) j++;
39         P[i] = j;
40     }
41 }
42 
43 int main(){
44     while(scanf("%s",s) != EOF){
45         if(s[0] == '.')
46             break;
47         len = strlen(s);
48         Get_P();
49         if(len % (len - P[len - 1] - 1) == 0) printf("%d\n",len / (len - P[len - 1] - 1));
50         else printf("1\n");
51     }
52     return 0;
53 }
View Code

 

   

posted @ 2014-12-13 00:14  Naturain  阅读(136)  评论(0编辑  收藏  举报