HDU 3746(KMP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1358
题意:给你一个字符串,要求将字符串的全部字符最少循环2次需要添加的字符数。 例子: abcabc 已经循环2次,添加数为0 abcac 没有循环2次,添加字符abcac。数目为5. abcabcab 已
经循环过2次,但第三次不完整,需要添加数为1 分析:还是用到了next数组,这个循环节这很巧妙啊。。。 做这个题需要好好理解KMP算法,尤其是next数组。
非优化的next数组的含义是:next[i]=k默示模式串下标为i的字符的前k-1个字符与开首的前k-1个字符相等,那么从1到i-1的模式串必定是轮回的,且循环节的长度为i-next[i].
理解了这一点这个题就很简单了。
总之 next含义是:
next[j]表代表j之前的字符串的真前缀和真后缀最大匹配长度 next[i]代表了前缀和后缀的最大匹配的值(需要彻底明白这点http://www.shengxun8.com/,相当重要)
非优化的next数组的含义是:next[i]=k默示模式串下标为i的字符的前k-1个字符与开首的前k-1个字符相等
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 5 const int N = 100002; 6 char str[N]; 7 int next[N]; 8 9 void get_next(int len) 10 { 11 int i = 0; 12 int j = -1; 13 next[i] = -1; 14 while(i < len) 15 { 16 if(j == -1 || str[i] == str[j]) 17 { 18 i++; 19 j++; 20 next[i] = j; 21 } 22 else 23 { 24 j = next[j]; 25 } 26 } 27 } 28 29 int main() 30 { 31 int t; 32 scanf("%d", &t); 33 while(t--) 34 { 35 scanf("%s", str); 36 int len = strlen(str); 37 get_next(len); 38 int x = len - next[len]; 39 if(len != x && (len % x == 0)) 40 { 41 printf("0\n"); 42 } 43 else 44 { 45 printf("%d\n", x - next[len] % x); 46 } 47 } 48 return 0; 49 }
参考别人的代码:
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 5 const int N = 100002; 6 char str[N]; 7 int next[N]; 8 9 void get_next(int len) 10 { 11 int i; 12 int j = 0; 13 for(next[1] = 0, i = 2; i <= len; i++) 14 { 15 while(j && str[j + 1] != str[i]) 16 { 17 j = next[j]; 18 } 19 if(str[j + 1] == str[i]) 20 { 21 j++; 22 } 23 next[i] = j; 24 } 25 } 26 27 int main() 28 { 29 int t; 30 scanf("%d", &t); 31 while(t--) 32 { 33 scanf("%s", str + 1); 34 int len = strlen(str + 1); 35 get_next(len); 36 int x = len - next[len]; 37 if(len % x == 0 && len != x) 38 { 39 printf("0\n"); 40 } 41 else 42 { 43 printf("%d\n", x - next[len] % x); 44 } 45 } 46 }
主要是next数组的求法不同,第一种是经过优化的,而第二种未经过优化。