POJ2406 & POJ1961 详细解题思路和AC程序 KMP算法变种

poj2406

题目大意:

给出一个字符串s,求其最短的子串a,使得s=a^n(即n个a相连),输出n。s的长度小于10^6。


Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3




本题可以用kmp算法来做。

先算出next数组。有些KMP算法的代码中next[i]代表的是s[i+1]匹配不上时下一个位置,有些代码代表的是s[i]匹配不上时,本人用后者,即next数组要求到'\0'那位。


len表示s的长度(不包括'\0'),那么如果确实有长度非len的解的话,该子串的最小长度一定为(len-next[len])。

以上不证明了(因为不会证),参考kmp算法的原理脑补一下:p

但长度为(len-next[len])的子串不一定真的是解。比如:abcab,len-next[len]=3,长度为3的串abc或者cab显然不是解

所以需要判断len%(len-next[len])==0是否成立。


够了吗? 那么是否有必要扫描一遍s,判断是否s中存在的确实是len/(len-next[len])个该子串呢?

够了。


如下图,表示len==12,next[len]==8时的情景,len-next[len]==4,可以发现s即为3个长度为4的子串构成的



参考程序:

#include <stdio.h>
#include <stdlib.h>
char s[1000010];
int next[1000010];

int kmp_next(char s[])
{
	int k=-1,j=0;
	next[j]=k;

	while (s[j])
	{
		if (k==-1 || s[k]==s[j])
		{
			k++;
			j++;
			if (s[k]==s[j])
				next[j]=next[k];
			else
				next[j]=k;
		}
		else k=next[k];
	}
	return j;
}

int main()
{
	int len,i,ans,flag,j;
	scanf("%s",s);
	while (s[0]!='.')
	{
		len=kmp_next(s);

		ans=(len-next[len]);
		if (len%ans!=0)
			ans=len;

		printf("%d\n",len/ans);
		scanf("%s",s);
	}
	return 0;
}


POJ1961


题目大意:

给出一个字符串的长度和字符串s,对于其所有的前缀,设其长度为i,求最大的k(k>=2),使a^k=substring(s,0,i),若存在这样的k,输出i,k

输出所有满足的i,k对


Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4




跟上题差不多,不过这回需要对next数组进行遍历。

同时注意求next数组的时候

			if (s[k]==s[j])
				next[j]=next[k];
			else
				next[j]=k;
如果有该优化的话,该优化得去掉,改成:

  next[j]=k;

原因见kmp算法原理




参考程序:



#include <stdio.h>
#include <stdlib.h>

char s[1000010];
int next[1000010];

void kmp_next(char s[])
{
	int k=-1,j=0;
	next[j]=k;

	while (s[j])
	{
		if (k==-1 || s[k]==s[j])
		{
			k++;
			j++;
			next[j]=k;
		}
		else k=next[k];
	}
}

int main()
{
	int tt,len,i,l,j=0;
	scanf("%d",&len);
	gets(s);
	while (len!=0)
	{
		gets(s);
		kmp_next(s);

		printf("Test case #%d\n",++j);
		for (i=2;i<=len;i++)
		{
			l=i-next[i];
			if (i%l==0 && i/l>1)
				printf("%d %d\n",i,i/l);
		}

		printf("\n");
		scanf("%d",&len);
		gets(s);
	}
	return 0;
}



需要做更基础的kmp题的可以去做poj3461,poj2752




阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/IceTeaSet/article/details/46811105
个人分类: 算法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

POJ2406 & POJ1961 详细解题思路和AC程序 KMP算法变种

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭