kmp2-HDU1358 HUST1010 POJ2406 POJ2752
HDU1358
http://acm.hdu.edu.cn/showproblem.php?pid=1358
?
先構造出 next[] 數組,下標為 i,定義一個變量?j = i - next[i]?就是next數組下標和下標對應值的差,如果這個差能整除下標 i,即 i%j==0 ,則說明下標i之前的字符串(周期性字符串長度為 i)一定可以由一個前綴周期性的表示出來,這個前綴的長度為剛才求得的那個差,即 j,則這個前綴出現的次數為?i/j?。
#include <iostream> #include <stdio.h> using namespace std; char a[1000010]; int next[1000010]; int n; void GetNext() //獲得a數列的next數組 {int i=0,k=-1;next[0] = -1;while(i<n){if(k==-1){next[i+1] = 0;i++;k++;}else if(a[i]==a[k]){next[i+1] = k+1;i++;k++;}elsek = next[k];} } void DisRes(int num) {int j;printf("Test case #%d\n",num);for(int i=0;i<=n;i++){if(next[i]==-1 || next[i]==0) //next[i]是-1或0的忽略,說明之前沒有周期性前綴continue;j = i - next[i];if(i%j==0) //能整除,說明存在周期性前綴printf("%d %d\n",i,i/j); //輸出這個前綴的長度和周期數}printf("\n"); } int main() {int num = 0;while(scanf("%d",&n)!=EOF){if(n==0) break;scanf("%s",a);GetNext(); //獲得next[]數組DisRes(++num); //輸出結果}return 0; }?
HUST 1010
http://www.hustoj.org/problem/1010
讀錯題了,B是減下來的那一堆,那就好做了。找最短循環節就可以了。(循環節:從某一位起向右進行到某一位止的一節數字循環出現,首尾銜接,稱這種小數為循環小數,這一節數字稱為循環節。)
#include<stdio.h> #include<string.h> #define N 1000005 char str[N]; int f[N]; void getFail(char *p, int *f) {int m=strlen(p);f[0]=f[1]=0;for(int i=1; i<m; ++i){int j=f[i];while(j && p[i]!=p[j])j=f[j];f[i+1] = p[i]==p[j]?1+j:0;} } int main() {while(scanf("%s",str)!=EOF){int len=strlen(str);getFail(str,f);printf("%d\n",len-f[len]);}return 0; }?POJ 2406
http://poj.org/problem?id=2406
?
大意:給出一個字符串 問它最多由多少相同的字串組成?
如 ?abababab由4個ab組成
最小循環節
ababab ?next[6] = 4; 即
ababab
? ?ababab
1~4位 ?與2~6位是相同的
?
那么前兩位
就等于3、4位
3、4位就等于5、6位
……
所以 如果 能整除 ?也就循環到最后了
?
如果不能整除 ?
就最后余下的幾位不在循環內
?
#include <iostream> #include <cstdio> #include <cstring> using namespace std;const int maxn = 1000005;int next[maxn];void get(char *s) {int l = strlen(s);int j = 0, k = -1;next[0] = -1;while(j < l) {if(k == -1 || s[j] == s[k]) {next[++j] = ++k;} else {k = next[k];}} } char s[maxn];int main() {while(gets(s) ) {if(strcmp(s,".") == 0) {break;}get(s);int ans = 1;int l = strlen(s);if(l % (l - next[l]) == 0) {ans = l / (l - next[l]);}printf("%d\n", ans);} }POJ2752
http://poj.org/problem?id=2752
大意:給定字符串S,求出S的所有可能相同前后綴的長度。比如:?
"alala"的前綴分別為{"a", "al", "ala", "alal", "alala"}, 后綴分別為{"a", "la", "ala", "lala", "alala"}. 其中有{"a", "ala", "alala"}是相同的,即輸入1,3,5.
思路:有了kmp算法的next數組(保存某段子串的相同前后綴的最大長度,不包括自身),可以從最長的相同前后綴開始考慮,對于串S,根據next[strlen(S)-1]得到的最長相同前后綴為S1,則再根據next[strlen(S1)-1]得到的S1的最長相同前后綴S2肯定也為S的相同前后綴。(通過畫圖可以很容易的證明)。?
????這樣,通過不斷的向前查找next數組,得到一系列的相同前后綴。下面證明這些前后綴包含了所有的相同前后綴:?
????????由于我們得到的是一系列最長相同前后綴,假設有一個相同的前后綴Sk不屬于這些通過next遞推得到的前后綴集合,那么len(Sk)必定小于len(S1),且Sk必定為S1的子串(通過畫圖很容易看出來);此時若Sk是S1的最長前后綴,則與前提Sk不為某一子串的最長前后綴矛盾,那么Sk不是S1的最長前后綴,則可以退出len(Sk)必定小于S2,且Sk必定為S2的相同前后綴..... 數學歸納遞推下去,可以知道Sk要么為某個Si的最長前后綴,要么len(Sk) = 0. 這樣可以證明這些通過next數組遞推得到的前后綴包含了所有的相同前后綴
?
總結
以上是生活随笔為你收集整理的kmp2-HDU1358 HUST1010 POJ2406 POJ2752的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Head First设计模式》第八章笔
- 下一篇: 二叉树最长路径