【HDOJ2087】剪花布条(KMP)

problem

  • 给定字符串A,B。求串A中可以分割出多少个互不相同的串B(不能重叠)。

solution

模板题,没啥好说的。
KMP匹配:如果成功,就把j==0,从头开始匹配,答案累加。

codes

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1010;

char a[maxn], b[maxn];
int n, m, Next[maxn], f[maxn];

void pre(){
    Next[1] = 0;
    int j = 0;
    for(int i = 1; i < m; i++){
        while(j>0 && b[i+1]!=b[j+1])j = Next[j];
        if(b[i+1]==b[j+1])j++;
        Next[i+1] = j;
    }
}
int kmp(){
    int ans = 0, j = 0;
    for(int i = 0; i < n; i++){
        while(j>0 && a[i+1]!=b[j+1])j = Next[j];
        if(a[i+1]==b[j+1])j++;
        f[i+1] = j;
        if(j==m)ans++, j = 0;
    }
    return ans;
}

int main(){
    while(cin>>a+1){
        if(a[1]=='#')break;
        scanf("%s",b+1);
        n = strlen(a+1);
        m = strlen(b+1);
        pre();
        printf("%d
",kmp());
    }
    return 0;
}

KMP

介绍:

字符串匹配问题:给定主串A和模式串B,求所有B在A中出现的位置。
传统做法:枚举A串从什么位置开始与B串匹配,然后验证是否匹配。最坏情况A=”aaaaaaaaaaaaaaab”,B=”aaaaaab”,复杂度O(mn)。
KMP:最坏情况复杂度O(n)

具体:
本质原理:

考虑情况(当前i==5):

i = 1 2 3 4 5 6 7 8 9
A = a b a b a b a a b a b
B = a b a b a c b
j = 1 2 3 4 5 6 7 8 9

对于下一个,不再匹配了。传统做法就是把B右移一位继续重头比较。
但是作为一个人,我一眼就看出了右移一位也不行,,,,于是,我们移到他下一个匹配的位置(最长的相同前缀和后缀)在开始比较。并且最好是这个匹配的长度尽可能长。

i = 1 2 3 4 5 6 7 8 9
A = a b a b a b a a b a b
B =     a b a b a c b
j =     1 2 3 4 5 6 7 8 9

再考虑到,B移动后的位置,相对A而言的位置关系,其实是和B移动前的位置关系是一样的(因为之前的时候AB匹配上了,所以是字母是完全一样的)。所以就变成了关于B的自我匹配,具体见下方。

两个步骤:

1、对模式串B进行自我匹配:求一个数组next,其中next[i]表示”B中以i结尾的非前缀子串”与“B的前缀”能匹配的最大长度。next[i]=max{j},j<iA[ij+1,i]=A[1,j]
2、对字符串A与B进行匹配:求一个数组f,其中f[i]表示”A中以i结尾的子串”与“B的前缀”能够匹配的最长长度。(当长度为B.size()时即得到答案)

具体求法:

1、求next:
咕咕咕

原文地址:https://www.cnblogs.com/gwj1314/p/10200110.html