hdu 3336
题意:输入一个字符串求每个前缀在串中出现的次数和
sol:只要稍微理解下next 数组的含义就知道只要把每个有意义的next值得个数加起来即可
PS:网上有dp解法orz,dp[i]表示以i为前缀串结尾的前缀串的总和,方程很容易写出
//字符串上KMP(水)
//从前向后扫,失配函数的位置就是一个前缀的位置减1
//加起来就好了
// by acvc
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX =
200000;
const int MOD =
10007;
char str[MAX];
int next[MAX],vis[MAX];
int main()
{
int cas,n;
scanf(
"%d",&cas);
while(cas--)
{
scanf(
"%d %s",&n,str);
next[
0]=next[
1]=
0;
for(
int i=
1;i<n;i++)
{
int j=next[i];
while(j&&str[i]!=str[j]) j=next[j];
if(str[i]==str[j])
next[i+
1]=j+
1;
else next[i+
1]=
0;
}
int ans=
0,cnt=
0;
for(
int i=
0;i<n;i++)
{
if(next[i])
{
// cnt++;
ans=(ans+
2)%MOD;
}
else ans=(ans+
1)%MOD;
}
if(next[n]) ans=(ans+
1)%MOD;
printf(
"%d\n",(ans)%MOD);
}
return 0;
}
hdu 1358
题意:给出一个字符串求出每个前缀的最小周期
sol:next数组理解题目稍微想想就知道t=(len-next[len])
//kmp小深入题目
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX =
10000000+
10;
char str[MAX];
int next[MAX];
//失配函数
int main()
{
int n,cnt=
0;
while(scanf(
"%d",&n)>
0)
{
scanf(
"%s",str);
next[
0]=next[
1]=
0;
for(
int i=
1;i<n;i++)
{
int j=next[i];
while(j&&str[i]!=str[j]) j=next[j];
if(str[i]==str[j]) next[i]=j+
1;
else next[i]=
0;
}
printf(
"Test case #%d\n",++cnt);
for(
int i=
2;i<=n;i++)
{
if(next[i]&&i%(i-next[i])==
0)
printf(
"%d %d\n",i,i%(i-next[i]));
}
}
return 0;
}
hdu1711
题意:给出两个数组,求出b在a中最先匹配的位置
sol:KMP裸题
1 //裸题
2 #include<cstring>
3 #include<cstdio>
4 #include<algorithm>
5 using namespace std;
6 const int MAX = 1e6+
10;
7 int next[MAX];
8 int a[MAX],b[MAX];
9 int main()
10 {
11 int cas,n,m;
12 scanf(
"%d",&cas);
13 while(cas--)
14 {
15 scanf(
"%d %d",&n,&m);
16 for(
int i=
0;i<n;i++) scanf(
"%d",&a[i]);
17 for(
int j=
0;j<m;j++) scanf(
"%d",&b[j]);
18 next[
1]=next[
0]=
0;
19 for(
int i=
1;i<m;i++)
20 {
21 int j=next[i];
22 while(j&&b[i]!=b[j]) j=next[j];
23 if(b[i]==b[j]) next[i+
1]=j+
1;
24 else next[i+
1]=
0;
25 }
26 int cur=
0,flag=
0;
27 for(
int i=
0;i<n;i++)
28 {
29 while(cur&&a[i]!=b[cur]) cur=next[cur];
30 if(a[i]==b[cur]) cur++;
31 if(cur==m)
32 {
33 flag=
1;
34 printf(
"%d\n",i-cur+
2);
35 break;
36 }
37 }
38 if(!flag) printf(
"-1\n");
39 }
40 return 0;
41 }
hdu2087
题意:给定串1和串2求串2在串1中出现的顺序
sol;裸KMP从前向后扫一遍kmp就好了
1 #include<cstring>
2 #include<algorithm>
3 #include<cstdio>
4 using namespace std;
5 const int MAX =
1000+
10;
6 char str1[MAX],str2[MAX];
7 int next[MAX];
8 int main()
9 {
10 while(scanf(
"%s",str1)&&strcmp(str1,
"#"))
11 {
12 int ans=
0;
13 scanf(
"%s",str2);
14 int n=strlen(str2); next[
0]=next[
1]=
0;
15 for(
int i=
1;i<n;i++)
16 {
17 int j=next[i];
18 while(j&&str2[i]!=str2[j]) j=next[j];
19 if(str2[i]==str2[j]) next[i+
1]=j+
1;
20 else next[i+
1]=
0;
21 }
22 int len=strlen(str1);
int j=
0;
23 for(
int i=
0;i<len;i++)
24 {
25 while(j&&str1[i]!=str2[j]) j=next[j];
26 if(str1[i]==str2[j]) j++;
27 if(j==n)
28 {
29 ans++;
30 j=
0;
31 }
32 }
33 printf(
"%d\n",ans);
34 }
35 return 0;
36 }
poj2406
题意:给定一个串求出串的最小周期
los:失配函数裸题啊
1 //kmp-shui
2 #include<cstring>
3 #include<algorithm>
4 #include<cstdio>
5 using namespace std;
6 const int MAX = 1e6+
10;
7 char str[MAX];
int next[MAX];
8 int main()
9 {
10 int ans;
11 while(
1)
12 {
13 gets(str);
if(!strcmp(str,
"."))
break;
14 int n=strlen(str); next[
0]=next[
1]=
0;
15 for(
int i=
1;i<n;i++)
16 {
17 int j=next[i];
18 while(j&&str[i]!=str[j]) j=next[j];
19 if(str[i]==str[j]) next[i+
1]=j+
1;
20 else next[i+
1]=
0;
21 }
22 if(n%(n-next[n])==
0)
23 printf(
"%d\n",n/(n-next[n]));
24 else printf(
"1\n");
25 }
26 return 0;
27 }
poj 2752
题意:给定一个串求出满足既是前缀又是后缀的串的起始位置
sol:又是一发next数组加深题目,很明显next数组指向的是最长的一个前缀串,所以最后一个指针指向的next就是一个最长前缀
之后从这个最长前缀末尾开始下一个指针又是前缀的最长前缀,而后缀和前缀相同,所以这个是第二长的前缀,只要递归结束即可
1 //kmp题目shui by acvc
2 //kmp每次都是求的最长的前缀
3 #include<cstring>
4 #include<algorithm>
5 #include<cstdio>
6 #include<vector>
7 using namespace std;
8 const int MAX = 400000+10;
9 int next[MAX];
10 char str[MAX];
11 vector<int> s;
12 int main()
13 {
14 while(scanf("%s",str)!=EOF)
15 {
16 s.clear();
17 int n=strlen(str); next[0]=0,next[1]=0;
18 for(int i=1;i<n;i++)
19 {
20 int j=next[i];
21 while(j&&str[i]!=str[j]) j=next[j];
22 if(str[i]==str[j]) next[i+1]=j+1;
23 else next[i+1]=0;
24 }
25 //for(int i=0;i<=n;i++) printf("%d ",next[i]);
26 // printf("\n");
27 int j=strlen(str);
28 while(j)
29 {
30 s.push_back(j);
31 j=next[j];
32 }
33 for(int i=s.size()-1;i>=0;i--)
34 {
35 if(i==s.size()-1) printf("%d",s[i]);
36 else printf(" %d",s[i]);
37 }
38 printf("\n");
39 }
40 return 0;
41 }
poj 2185
题意:输入一个矩阵由字符组成,求出矩阵的最小组成单位。
sol:这道题没解出来,参考网上代码。其实也是一个next数组理解题目,只不过变成二维看起来比较牛x而已
我们对每行和每列分别求出其对应的周期然后对行取下最小公倍数,对列取下最小公倍数即可,当公倍数大于边界时要特判
1 #include<iostream>
2 #include<stdio.h>
3 using namespace std;
4 char s[
10005][
80];
5 int subrow[
10005];
6 int subcol[
80];
7 int next[
10005];
8 int row,col;
9 int nextrow(
int r)
10 {
11 int i=
0,j=-
1;
12 next[
0]=-
1;
13 while(i<col)
14 {
15 if(j==-
1||s[r][i]==s[r][j])
16 {
17 i++;j++;
18 next[i]=j;
19 }
20 else21 j=next[j];
22 }
23 return i-next[i];
24 }
25 int nextcol(
int c)
26 {
27 int i=
0,j=-
1;
28 next[
0]=-
1;
29 while(i<row)
30 {
31 if(j==-
1||s[i][c]==s[j][c])
32 {
33 i++;j++;
34 next[i]=j;
35 }
36 else37 j=next[j];
38 }
39 return i-next[i];
40 }
41 42 int LCM(
int a,
int b)
43 {
44 int x=a,y=b;
45 int r=x%y;
46 while(r>
0)
47 {
48 x=y;
49 y=r;
50 r=x%y;
51 }
52 return a*b/y;
53 }
54 int main()
55 {
56 while(scanf(
"%d%d",&row,&col)==
2)
57 {
58 for(
int i=
0;i<row;i++)
59 scanf(
"%s",s[i]);
60 for(
int i=
0;i<row;i++)
61 subrow[i]=nextrow(i);
62 for(
int i=
0;i<col;i++)
63 subcol[i]=nextcol(i);
64 int x=
1;
65 for(
int i=
0;i<row;i++)
66 x=LCM(x,subrow[i]);
67 if(x>col)
68 x=col;
69 int y=
1;
70 for(
int i=
0;i<col;i++)
71 y=LCM(y,subcol[i]);
72 if(y>row)
73 y=row;
74 printf(
"%d\n",x*y);
75 }
76 return 0;
77 }
hdu poj KMP简单题目总结
原文:http://www.cnblogs.com/acvc/p/3539060.html