想法的来源!!!!!!
不懂kmp?请看上面的链接,附上一道模板题 洛谷P3375
这是一道kmp(mp?我也分不清)的模板题(紫书上好像有类似的模板),思路很清楚,下面放出代码
解题
#include <bits/stdc++.h>
#include <ctime>
using namespace std;
clock_t _timer_start,_timer_end;
void start_timer(){
_timer_start=clock();
}
void stop_timer(){
_timer_end=clock();
double dur=(double)(_timer_end-_timer_start);
printf("Time Consume:%lf second\n", dur/CLOCKS_PER_SEC);
}
/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
char src[101010],pattern[101010];
int fail[101010];
void calc_fail(){
fail[0]=0;
int len=strlen(pattern+1);
int k=0;
for(int i=1;i<=len;i++){
while(k && pattern[i]!=pattern[k])k=fail[k];
//下面这一行的有无不影响程序的正确性
//while(k && pattern[i+1]==pattern[k])k=fail[k];
fail[i+1]= pattern[i]==pattern[k]?++k:0;
}
}
long long jump=0;
long long ans=0;
void solve(){
calc_fail();
int l1,l2;
l1=strlen(src), l2=strlen(pattern);
int cnt=0;
for(int i=0,j=0;i<l1;){
//jump++;
if(src[i]==pattern[j]){
j++;i++;
if(j==l2){
cnt++;
j=0;
}
}else{
if(j!=0)j=fail[j];
else i++;
}
}
//ans+=cnt;
printf("%d\n", cnt);
}
int main() {
//start_timer();
while(scanf("%s%s", src, pattern)==2 && src[0]!='#')solve();
//stop_timer();
//printf("process %lld ans %lld", jump, ans);
}
题目很简单。
开始折腾自己
我在其他博客看到的kmp(mp?)代码大都如上,但是这样的代码存在一个问题:
举个例子
原串(T): aaacaaaa
匹配串(P): aaaa
可以自己模拟一下:
前三个字符都是匹配的
接下来遇到第四个字符,发现
那么我们的算法会怎么处理呢?很明显,,所以程序会用T[3]与P[2]进行判断。那么问题来了, 我们已经知道了 == ‘a’,那么让程序再跳回位置2显然是浪费的。
既然发现了问题,那。。。
写数据卡自己的代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
#define produce 1
#if produce==1
void redirect_output(char * path){
freopen(path,"w",stdout);
}
const int kase=10000;
void output();
int ran(int l,int r){
return double(rand())/RAND_MAX*(r-l)+l;
}
int main(){
srand(time(NULL));
redirect_output("/home/lalala/in");
if(kase==0){
output();
}else{
//printf("%d\n",kase);
for(int i=0;i<kase;i++) output();
printf("#\n");
}
}
void output(){
int len1,len2;
len1 = ran(1, 100000);
len2 = len1/10;
len2 = ran(1, min(1000, len1));
for(int i=0;i<len1;i++){
int r=ran(0,60);i+=r;
for(int j=0;j<r;j++)printf("%c",'a');
r=ran(0,4);i+=r;
for(int j=0;j<r;j++)printf("%c",'c');
}
printf("\n");
for(int i=0;i<len2;i++){
printf("a");
}
printf("\n");
}
#endif
生成了489M的数据 (`・ω・´)
用我们的代码跑一下试试
还不错,用时3.24s
小优化
我们做一点小优化,如下(就是把注释掉的代码恢复 T_T)
void calc_fail(){
fail[0]=0;
int len=strlen(pattern+1);
int k=0;
for(int i=1;i<=len;i++){
while(k && pattern[i]!=pattern[k])k=fail[k];
//下面这一行的有无不影响程序的正确性
while(k && pattern[i+1]==pattern[k])k=fail[k];
fail[i+1]= pattern[i]==pattern[k]?++k:0;
}
}
那么现在再跑一下呢?
1.98s,快乐呀
总结
当我们发现P[i+1]==P[k]时,可以肯定P[fail[k]]!=P[i+1],于是我们可以继续让k=fail[k]
加一点小优化,遇上毒瘤题也不怕啦~~
Ps. 本垃圾刷的题少T_T,暂时没见过卡这点的题目
更新
貌似这就是kmp与mp的区别
见 https://www.cnblogs.com/NightRaven/p/10554401.html