洛谷 P3375 【模板】KMP字符串匹配 || HDU 1686 Oulipo || kmp

HDU-1686

P3375

kmp介绍:

http://www.cnblogs.com/SYCstudio/p/7194315.html

http://blog.chinaunix.net/uid-8735300-id-2017161.html(mp&kmp)

http://www-igm.univ-mlv.fr/~lecroq/string/node8.html(mp&kmp,看上去很正确的例程)

http://blog.csdn.net/joylnwang/article/details/6778316

洛谷P3375:

字符串下标从1开始:

 1 #include<cstdio>
 2 #include<cstring>
 3 char s1[1000010],s[1010];
 4 int f[1010];
 5 int n,m;
 6 void getf()
 7 {
 8     int i,j=0;
 9     f[0]=-1;f[1]=0;
10     for(i=2;i<=m;i++)
11     {
12         //j=f[i-1]其实开始的时候j是这个值
13         while(j>=0&&s[j+1]!=s[i])    j=f[j];
14         j++;
15         /*这一步后就是满足s[1..j]==s[i-j+1..i]
16         显然如果找不到任何j那么j应该为0,而-1+1=0,所以f[0]=-1,
17         否则应当为s[1..i-1]的某个相同的前缀后缀且它们之后都为s[i]*/
18         f[i]=j;
19     }
20 }
21 void kmp()
22 {
23     int ans=0,i,j=0;
24     for(i=1;i<=n;i++)
25     {
26         //初始时j为s[1..j]==s[i-1-j+1..i-1]
27         while(j>=0&&s[j+1]!=s1[i])    j=f[j];
28         j++;
29         //此时使得s往后移到了正确的位置
30         /*例如ABABABC/ABC:i=3时j=1,也就是s开头1位跟s1[1..i]对齐
31         又如ABDBA/ABC:i=3时j=0,也就是s开头0位跟s1[1..i]对齐*/
32         if(j==m)
33         {
34             //ans++;
35             printf("%d\n",i-m+1);
36             j=f[j];
37         }
38     }
39     //return ans;
40 }
41 int main()
42 {
43     int i;
44     scanf("%s%s",s1+1,s+1);
45     n=strlen(s1+1);
46     m=strlen(s+1);
47     getf();
48     kmp();
49     for(i=1;i<=m;i++)
50         printf("%d ",f[i]);
51     return 0;
52 }

字符串下标从0开始,加上某个优化后开两个f:

 1 #include<cstdio>
 2 #include<cstring>
 3 int f[1010],f2[1010];
 4 char s1[1000100],s[1010];
 5 int n,m;
 6 void getf()
 7 {
 8     int i=0,j=f[0]=-1;
 9     while(i<m)
10     {
11         while(j>=0&&s[j]!=s[i])    j=f[j];
12         ++i;++j;
13         f[i]=s[i]==s[j]?f[j]:j;
14         f2[i]=j;
15     }
16 }
17 void kmp()
18 {
19     int i=0,j=0;
20     while(i<n)
21     {
22         while(j>=0&&s[j]!=s1[i])    j=f[j];
23         ++i;++j;
24         if(j==m)    printf("%d\n",i-m+1);
25     }
26 }
27 int main()
28 {
29     int i;
30     scanf("%s%s",s1,s);
31     n=strlen(s1);
32     m=strlen(s);
33     getf();
34     kmp();
35     for(i=1;i<=m;i++)
36         printf("%d ",f2[i]);
37     return 0;
38 }

HDU-1686:

程序1的f[i]的含义是能使s[0..p-1]==s[i-p..i-1]的最大的p。字符串下标从0开始。也就是如果当对齐原串下标i的是模板串下标j时发生失配,可以将对齐原串下标i的改为模板串下标f[j]。

程序1(蓝书模板)(f[0]定义为0):

 1 #include<cstdio>
 2 #include<cstring>
 3 int f[10100];
 4 char s1[1000100],s[10100];
 5 void getFail(char *P,int *f)
 6 {
 7     int m=strlen(P);
 8     f[0]=0;f[1]=0;
 9     for(int i=1;i<m;i++)
10     {
11         int j=f[i];
12         while(j&&P[i]!=P[j])    j=f[j];
13         f[i+1]=P[i]==P[j]?j+1:0;
14     }
15 }
16 int find(char *T,char *P,int *f)
17 {
18     int n=strlen(T),m=strlen(P),ans=0;
19     getFail(P,f);
20     int j=0;
21     for(int i=0;i<n;i++)
22     {
23         while(j&&P[j]!=T[i])    j=f[j];
24         if(P[j]==T[i])    j++;
25         if(j==m)    ans++;
26     }
27     return ans;
28 }
29 int main()
30 {
31     int t;
32     scanf("%d",&t);
33     while(t--)
34     {
35         scanf("%s%s",s,s1);
36         printf("%d\n",find(s1,s,f));
37     }
38     return 0;
39 }

程序2(魔改蓝书&某个例程)(f[0]定义为-1,已经加了某个优化):

 1 #include<cstdio>
 2 #include<cstring>
 3 int f2[10100];
 4 char s1[1000100],s[10010];
 5 void getFail(char *P,int *f)
 6 {
 7     int m=strlen(P),j=f[0]=-1,i=0;//i初始值不能为1
 8     while(i<m)
 9     {
10         while(j>=0&&P[i]!=P[j])    j=f[j];
11         ++j;++i;
12         f[i]=P[i]==P[j]?f[j]:j;
13     }
14 }
15 int find(char *T,char *P,int *f)
16 {
17     int n=strlen(T),m=strlen(P),ans=0;
18     getFail(P,f);
19     int i=0,j=0;
20     while(i<n)
21     {
22         while(j>=0&&P[j]!=T[i])    j=f[j];
23         ++i,++j;
24         if(j==m)    ans++;//本来还有一句j=f[j],但这句可以去掉,因为此时j==m,P[j]==‘\0‘,一定不等于T[i],一定执行j=f[j]
25     }
26     return ans;
27 }
28 int main()
29 {
30     int t;
31     scanf("%d",&t);
32     while(t--)
33     {
34         scanf("%s%s",s,s1);
35         printf("%d\n",find(s1,s,f2));
36     }
37     return 0;
38 }

为什么当s[i]!=s[j]时,j=f[j]:

http://blog.csdn.net/qq_30974369/article/details/74276186

http://blog.csdn.net/yutianzuijin/article/details/11954939/

http://blog.csdn.net/wangbaochu/article/details/50687160

(要求从next[i]一段的末尾找到一段k,使得k和(开头的next[i]开头的)一段相同。也就是在next[i]的一段中找出开头和结尾相等的一段。(根据第2、3个博客的图))

将各个段从左到右编号为1(灰)、2(紫)、3(红)、4(灰)、5(绿)、6(黑)、7(灰)、8(红)、9(灰)、10(蓝)、11(黑)。

现在的情况是要寻找1-10这大段的最长公共前后缀。用f[n]表示1-n这一段的最长公共前后缀(或其长度),s[n]表示n位置的值。

如果s[5]==s[10],那么显然1-10的公共前后缀可以是f[9]的后面加上一个10。

可以证明这就是1-10的最长公共前后缀:如果不是,也就是f[10]>f[9]+1,也就是f[10]-1>f[9],那么将f[10]删除尾部的s[10],剩下长度为f[10]-1,那么剩下的部分是1-9的公共前后缀,且其长度大于f[9],矛盾。

如果s[5]!=s[10],那么就是要在1-9中找出1-x使得1-x一段是1-9的公共前后缀且s[x+1]==s[10]。

先考虑第一个条件,再去满足第二个:那么也就是要找出1段和9段相同且不等于1-4段。由于1-4段和7-9段是1-9段的公共前后缀,那么1-4段==7-9段,也就是可以在7-9段中找到7段对应1段,在1-4段中找到4段对应9段。可以知道1、4、7、9段都相等。

由于1、4段相等,1、4段也是1-4这一段的公共前后缀。因此可以直接找f[4],结果也就是1-9段的次长公共前后缀。如果还是不行,就找f[f[4]],f[f[f[4]]],...

时间: 2024-10-03 22:15:54

洛谷 P3375 【模板】KMP字符串匹配 || HDU 1686 Oulipo || kmp的相关文章

洛谷P3375 [模板]KMP字符串匹配

To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整

HDU - 1686 Oulipo KMP匹配运用

HDU - 1686 Oulipo Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description The French author Georges Perec (1936?1982) once wrote a book, La disparition, without the letter 'e'. He was a member of the Ouli

hdu 1686 Oulipo kmp算法

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1686 题目: Problem Description The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e'. He was a member of the Oulipo group. A quote from the book: Tout avait

HDU - 1686 Oulipo (KMP)

Problem Description The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e'. He was a member of the Oulipo group. A quote from the book: Tout avait Pair normal, mais tout s'affirmait faux. Tout avait Fair

(KMP 1.2)hdu 1686 Oulipo(计算模式串在文本串中出现的次数)

题目: Oulipo Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5985    Accepted Submission(s): 2404 Problem Description The French author Georges Perec (1936–1982) once wrote a book, La disparition,

Luogu P3375 【模板】KMP字符串匹配

P3375 [模板]KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整数

P3375 模板 KMP字符串匹配

P3375 [模板]KMP字符串匹配 来一道模板题,直接上代码. #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 5; int n, m; char s1[N], s2[N]; int nxt[N] ; void Get_next(char *s) { int j, L = strlen(s + 1); nxt[1] = j = 0; for(int i = 2; i

AC自动机(附洛谷P3769模板题)

首先,介绍一下AC自动机(Aho-Corasick automaton),是一种在一个文本串中寻找每一个已给出的模式串的高效算法. 在学习AC自动机之前,你需要先学习Trie树和KMP算法,因为AC自动机正式利用并结合了两者的思想. 说到实际的不同,其实AC自动机只是在Trie树上引入了一个类似KMP中next数组的东西叫做Fail指针. 对于每一个节点,Fail指针指向该节点所代表的字符串中,次长的.在Trie树中存在的后缀(因为最长的在Trie树种存在的后缀就是其本身)所代表的节点. 举例:

KMP字符串匹配

1 #include<iostream> 2 3 4 using namespace std; 5 6 #define MAX 255 7 8 typedef unsigned char BYTE; 9 10 typedef BYTE String[MAX+1]; 11 12 bool strAssign(String& strTemp,char* Temp); //定长字符串存储 13 bool strTravel(String& strTemp); //打印 14 void