HDU-1686

P3375

kmp介绍:

http://www.matrix67.com/blog/archives/115

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开始:

 #include<cstdio>
#include<cstring>
char s1[],s[];
int f[];
int n,m;
void getf()
{
int i,j=;
f[]=-;f[]=;
for(i=;i<=m;i++)
{
//j=f[i-1]其实开始的时候j是这个值
while(j>=&&s[j+]!=s[i]) j=f[j];
j++;
/*这一步后就是满足s[1..j]==s[i-j+1..i]
显然如果找不到任何j那么j应该为0,而-1+1=0,所以f[0]=-1,
否则应当为s[1..i-1]的某个相同的前缀后缀且它们之后都为s[i]*/
f[i]=j;
}
}
void kmp()
{
int ans=,i,j=;
for(i=;i<=n;i++)
{
//初始时j为s[1..j]==s[i-1-j+1..i-1]
while(j>=&&s[j+]!=s1[i]) j=f[j];
j++;
//此时使得s往后移到了正确的位置
/*例如ABABABC/ABC:i=3时j=1,也就是s开头1位跟s1[1..i]对齐
又如ABDBA/ABC:i=3时j=0,也就是s开头0位跟s1[1..i]对齐*/
if(j==m)
{
//ans++;
printf("%d\n",i-m+);
j=f[j];
}
}
//return ans;
}
int main()
{
int i;
scanf("%s%s",s1+,s+);
n=strlen(s1+);
m=strlen(s+);
getf();
kmp();
for(i=;i<=m;i++)
printf("%d ",f[i]);
return ;
}

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

 #include<cstdio>
#include<cstring>
int f[],f2[];
char s1[],s[];
int n,m;
void getf()
{
int i=,j=f[]=-;
while(i<m)
{
while(j>=&&s[j]!=s[i]) j=f[j];
++i;++j;
f[i]=s[i]==s[j]?f[j]:j;
f2[i]=j;
}
}
void kmp()
{
int i=,j=;
while(i<n)
{
while(j>=&&s[j]!=s1[i]) j=f[j];
++i;++j;
if(j==m) printf("%d\n",i-m+);
}
}
int main()
{
int i;
scanf("%s%s",s1,s);
n=strlen(s1);
m=strlen(s);
getf();
kmp();
for(i=;i<=m;i++)
printf("%d ",f2[i]);
return ;
}

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):

 #include<cstdio>
#include<cstring>
int f[];
char s1[],s[];
void getFail(char *P,int *f)
{
int m=strlen(P);
f[]=;f[]=;
for(int i=;i<m;i++)
{
int j=f[i];
while(j&&P[i]!=P[j]) j=f[j];
f[i+]=P[i]==P[j]?j+:;
}
}
int find(char *T,char *P,int *f)
{
int n=strlen(T),m=strlen(P),ans=;
getFail(P,f);
int j=;
for(int i=;i<n;i++)
{
while(j&&P[j]!=T[i]) j=f[j];
if(P[j]==T[i]) j++;
if(j==m) ans++;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",s,s1);
printf("%d\n",find(s1,s,f));
}
return ;
}

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

 #include<cstdio>
#include<cstring>
int f2[];
char s1[],s[];
void getFail(char *P,int *f)
{
int m=strlen(P),j=f[]=-,i=;//i初始值不能为1
while(i<m)
{
while(j>=&&P[i]!=P[j]) j=f[j];
++j;++i;
f[i]=P[i]==P[j]?f[j]:j;//改为f[i]=j就是没有优化
}
}
int find(char *T,char *P,int *f)
{
int n=strlen(T),m=strlen(P),ans=;
getFail(P,f);
int i=,j=;
while(i<n)
{
while(j>=&&P[j]!=T[i]) j=f[j];
++i,++j;
if(j==m) ans++;//本来还有一句j=f[j],但这句可以去掉,因为此时j==m,P[j]=='\0',一定不等于T[i],一定执行j=f[j]
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",s,s1);
printf("%d\n",find(s1,s,f2));
}
return ;
}

为什么当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]]],...

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

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

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

  2. HDU - 1686 Oulipo KMP匹配运用

    id=25191" target="_blank" style="color:blue; text-decoration:none">HDU - ...

  3. hdu 1686 Oulipo KMP匹配次数统计

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1686 分析:典型的KMP算法,统计字符串匹配的次数. 用Next数组压缩时间复杂度,要做一些修改. / ...

  4. HDU 1686 - Oulipo - [KMP模板题]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1686 Time Limit: 3000/1000 MS (Java/Others) Memory Li ...

  5. hdu 1686 Oulipo kmp算法

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1686 题目: Problem Description The French author George ...

  6. hdu 1686 Oulipo (kmp)

    Problem Description The French author Georges Perec (1936–1982) once wrote a book, La disparition, w ...

  7. HDU 1686 Oulipo (KMP 可重叠)

    题目链接 Problem Description The French author Georges Perec (1936–1982) once wrote a book, La dispariti ...

  8. HDU 1686 Oulipo kmp裸题

    kmp算法可参考 kmp算法 汇总 #include <bits/stdc++.h> using namespace std; const int maxn=1000000+5; cons ...

  9. KMP字符串匹配 模板 洛谷 P3375

    KMP字符串匹配 模板 洛谷 P3375 题意 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.(如果 ...

随机推荐

  1. window批处理-5 start

    作用 又一次启动一个单独窗体.在新窗体中运行命令 格式 start [/w] FileName demo bat: @echo off echo 在新窗体中打开txt文件.并等待新窗体正常退出(exi ...

  2. armel、armhf和arm64

    1 这些名词是什么的缩写 1.1 armel 是arm eabi little endian的缩写.eabi是软浮点二进制接口,这里的e是embeded,是对于嵌入式设备而言. 1.2 armhf 是 ...

  3. POJ2942 Knights of the Round Table 点双连通分量 二分图判定

    题目大意 有N个骑士,给出某些骑士之间的仇恨关系,每次开会时会选一些骑士开,骑士们会围坐在一个圆桌旁.一次会议能够顺利举行,要满足两个条件:1.任意相互憎恨的两个骑士不能相邻.2.开会人数为大于2的奇 ...

  4. 为了cider,尝试emacs的坑

    https://github.com/clojure-emacs/cider http://clojure-doc.org/articles/tutorials/emacs.html emacs通过b ...

  5. Dedecms(织梦)文章内容页和图片集内容页,调用缩略图的方法

    Dedecms(织梦)文章内容页和图片集内容页,调用缩略图的方法,亲测可用! Dedecms(织梦)首页的图片调用,相信大家已经非常的清楚,但是今天我在进行内容页的编写的时候,发现了内容页图片的调用问 ...

  6. Java中的Lock

    同步机制是Java并发编程中最重要的机制之一,锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能防止多个线程同时访问共享资源(但是也有例外,比如读写锁).Java中可以使用synchroniz ...

  7. zoj 3204 Connect them(最小生成树)

    题意:裸最小生成树,主要是要按照字典序. 思路:模板 prim: #include<iostream> #include<stdio.h> #include<string ...

  8. I.MX6 u-boot 2009 lvds hdmi lcd 补丁

    /************************************************************************* * I.MX6 u-boot 2009 lvds ...

  9. python-----实现print不换行

    python中print输出是默认换行的,那如何我们不想换行,且需要用多个print函数输出时,就需要改变print默认换行的属性: 例: print('Hello') print('!') 输出结果 ...

  10. 字体的设置 REM EM PX

    px 1 一般设置页面的字体使用px 2 优点:字体设置比较稳定和精确 3 缺点:他会修改用户浏览器中的字体大小 EM 相对于父元素的字体大小,字体大小不确定,容易混乱,“em”是相对于其父元素来设置 ...