Period hdu 1358 KMP的使用

又开拓了一点点视野。。。。KMP的使用,想当初,看KMP看了我一个多星期啊,总算没白看。KMP中的next数组的含义我想大家应该都知道吧,如果不知道的话,还是建议去书上理解下KMP,简单说一下。KMP中的next数组表示:以当前第i个字符为结尾的字符串,与从第一个字符开始,与第i个字符相等的字符为结尾的字符串,最长能匹配的长度。举个例子:s = ababa。下标从0开始。next[0] = 0,因为它前面没有字符了。next[1] = 0.因为b和a不相等。next[2] = 1,因为a 和第一个字符相等,但是ba != ab。next[3] = 2,因为以b为结尾的ab == 以一个字符开头,以跟第i个字符相等的‘b’结尾的最长长度字符串等于ab。next[4] = 3,因为前面三个字符串aba 等于后三个字符串aba。我们把一个循环节看成一个点或者一个字符,每个点就是一个循环节。

下面这幅图,假设next[3] = 2,也就是说2号点等于1号点,3号点等于2号点,在图中就是下划线为两条的字符串等于下划线为一条的字符串。那么肯定2号点等于1号点,3号点等于2号点,那么3号点也肯定等于1号点,也就是说1,2,3号点都相等,正好满足我们的要求:一个字符串重复若干次,下面这幅图就是点1代表的字符串重复了3次。点3代表的字符串的长度就是循环节的长度。next【3】表示的就是循环节循环的次数。但是如果点3代表的字符串的长度不等于循环节的长度,那么这个字符串就不是一个周期字符串。点3的长度可以用i - next[i]+1得到,而循环次数则是(i+1)/(i - next[i]+1)


#include<stdio.h>
#include<memory>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;

char str[1000005];
int next[1000005];

int main()
{
	int icase = 1,n,p;
	while(scanf("%d",&n),n)
	{
		printf("Test case #%d\n",icase++);
		scanf("%s",str);
		next[0] = 0;
		for(int i = 1;i < n;++i)
		{
			p = next[i-1];
			//这是求next[i]的值
			while(true)
			{
				if(str[i] == str[p])
				{
					next[i] = p+1;
					break;
				}
				if(p == 0)
				{
					if(str[i] != str[0])
						next[i] = 0;
					break;
				}
				p = next[p-1];
			}
			//根据next【i】的值跟上面的推论得出答案。
			if(next[i] != 0 && next[i]%(i - next[i]+1) == 0)
				printf("%d %d\n",i+1,(i+1)/(i - next[i]+1));
		}
		printf("\n");
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/a549875231/article/details/10066051