一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?
Input输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。
Output输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。
Sample Input
abcde a3 aaaaaa aa #Sample Output
0 3c代码:
kmp匹配单个字符串。
kmp的大概意思是,对于对照串(匹配对照用),Next记录到第i各字符时最大前缀后缀匹配个数,然后在对主串找和对照串匹配的子串时,如果到某个字符位置j发现不相同,并不需要从开头的下一个字符开始匹配,因为Next[j]记录了最大前缀后缀匹配数,此次是从前缀开始匹配的,下一次只需要从后缀开始就好了,模板串前移j - Next[j]位,
举个例子主串s,对照串p,s = "abcdabe",p = "abcdabc",从头开始匹配,发现匹配到第6位时(下标从0开始),'e' != 'c',此时s还在第五位,p也是,此时不需要从s的第1位开始匹配p串,而是从第4位开始,而且第4、5位匹配过了,p串只需要从第2位开始就好了,因为此时最大前缀后缀匹配数为2,也确实是这样。这就是Next数组的作用。
#include <stdio.h> #include <stdlib.h> #include <string.h> void findnext(char *str,int *Next) {///找最大前缀后缀匹配数 int i = 0,j = -1,len = strlen(str); Next[0] = -1;///初始为-1 while(i < len) { if(j == -1 || str[i] == str[j]) { Next[++ i] = ++ j; } else j = Next[j]; } } int kmp(char *s,char *p) { int Next[1000],ans = 0; int slen = strlen(s),plen = strlen(p); findnext(p,Next); int i = -1,j = -1; while(i < slen) { if(j == -1 || s[i] == p[j]) { i ++,j ++; if(j == plen) { ans ++; j = 0;///j归0 从头开始匹配 } } else j = Next[j]; } return ans; } int main() { char s[1000],p[1000]; while(~scanf("%s",s)&&strcmp(s,"#")) { scanf("%s",p); printf("%d ",kmp(s,p)); } }
用c++ string类写了一下,不用像kmp考虑那么累
c++代码:
#include <iostream> #include <string> using namespace std; int check(string a,string b) { int d = b.size(),ans = 0; int size = a.size() - d + 1; string t; for(int i = 0;i <= size;i ++) { if(a[i] == b[0]) { t.assign(a,i,d); if(t == b) { ans ++; i += d - 1; } } } return ans; } int main() { string a,b; while(cin>>a&&a!="#") { cin>>b; cout<<check(a,b)<<endl; } }