题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=2087
Problem Description
一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?
Input
输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。
Output
输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。
Sample Input
abcde a3
aaaaaa aa
Sample Output
0
3
题目的意思是求一个字符串a中包含多少个子串b,除了暴力的二层循环查找外,还可以采用KMP算法
KMP算法是一种改的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。
KMP的核心:PMT(Partical Match Table)部分匹配表,也就是求nexts数组
PMT里面的值代表了前缀与后缀的集合交集中元素的最大长度
这里采用模式串自己与自己匹配求得PMT
AC代码:
#include <iostream>
using namespace std;
const int MAXN = 1010;
int nexts[MAXN];
void getnext(string a)
{
nexts[0]=-1;
int i=0,j=-1;
while(i<a.length())
{
if(j==-1||a[i]==a[j])
{
i++;j++;
nexts[i]=j;
}
else
{
j=nexts[j];
}
}
}
int KMP(string a,string b)
{
int ans=0;
int i=0,j=0;
while(i<a.length())
{
if(j==-1||a[i]==b[j])
{
i++;
j++;
}
else
{
j=nexts[j];
}
if(j==b.length())
{
ans++;
j=0;
}
}
return ans;
}
int main()
{
string a,b;
while(cin>>a&&a[0]!='#')
{
cin >> b;
getnext(b);
cout << KMP(a,b) << endl;
}
return 0;
}