hdu3746 KMP深度认识next函数

来源:互联网 发布:方便面在美国监狱知乎 编辑:程序博客网 时间:2024/05/16 05:07

Cyclic Nacklace

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 902    Accepted Submission(s): 386


Problem Description
CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of "HDU CakeMan", he wants to sell some little things to make money. Of course, this is not an easy task.

As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl's fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls' lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet's cycle is 9 and its cyclic count is 2:

Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden.
CC is satisfied with his ideas and ask you for help.
 

Input
The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases.
Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by 'a' ~'z' characters. The length of the string Len: ( 3 <= Len <= 100000 ).
 

Output
For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.
 

Sample Input
3aaaabcaabcde
 

Sample Output
025

题意:给你一个字符串,要求将字符串的全部字符最少循环2次需要添加的字符数。例子:abcabc 已经循环2次,添加数为0abcac 没有循环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个字符相等

 

我的代码:

#include<stdio.h>#include<string.h>int d;char a[100005];int next[100005];void get_next(){ int i=1,j=0; next[1]=0; while(i<=d) {  if(j==0||a[i]==a[j]){i++;j++;next[i]=j;}  else j=next[j]; }}int main(){ int t,k; scanf("%d",&t); getchar(); while(t--) {  gets(a+1);  d=strlen(a+1);  get_next();   /*next[i]=k模式串下标为i的字符的前k-1个字符与开首的前k-1个字符相等*/  // printf("next=%d\n",next[d+1]-1);  //此时next[d+1]=k 即d+1之前有k-1个相等 所以减1 得到next[d+1]-1 即为包括d在内的子串与前面开首重复的个数  k=d-(next[d+1]-1);//k是一个循环的大小 因为随着循环次数的增加next[d+1]也相应的增加一个循环  //因为这些字符都是重复的 且不能构成一个节的也是这个节的子串 next[d+1]-1就是这个节的子串 然后用d减去后得到的就是节的长度  if(k!=d&&d%k==0)   printf("0\n");  else   printf("%d\n",k-(next[d+1]-1)%k); } return 0;}/*next[j]表代表j之前的字符串的真前缀和真后缀最大匹配长度  如abcdeabcdea 重复串为abcdea 最大匹配为6 即next[d+1]=6;*/

 

 

网上流行代码:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int M=100002;char s[M];int next[M];void get_next(int len)  // kmp 模板{    int i=0,j=-1;    next[0]=-1;    while(i<len)    {        if(s[i]==s[j] || j==-1)            next[++i]=++j;        else            j=next[j];    }}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%s",s);        int len=strlen(s);  // 若有一个字符串s的长度为 len ,        get_next(len);        int min_repeat_len=len-next[len]; // 那 len-next[len] 就是最小的循环节的长度  if(len!=min_repeat_len&&len%min_repeat_len==0 ) // 能整除,即表示字符串已经循环了 但是像a这种只要加1个a即可      //所以要排除这种情况             printf( "0\n" );        else           // 最小的循环节的长度 - 多出来的字符(串)即为所求            printf( "%d\n", min_repeat_len-len%min_repeat_len );    }    return 0;} 

 
原创粉丝点击