题解报告:hdu 2087 剪花布条(KMP入门)

题目链接: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

解题思路:这是一道KMP入门题,设计出这个算法的人真的太聪明了,菜鸡佩服得五体投地,字符串匹配过程真的太巧妙了!!!这道题就是给你一个主串和一个模式串,要求从主串找出没有交集的相同模式串的最大数量。一开始很容易想到暴力枚举,不过会超时,时间复杂度是O(nm),况且题目给出的字符串长度不超过10^3,最坏的时候是10^6基本算是超时的了。所以还不如花多点时间学习新的算法思想,争取在做题中灵活应用。对于KMP的讲解,目前有一篇大牛写的算是賊好理解了,这里贴一下大神之作(菜鸡仰慕):这个算法时间复杂度是O(n+m),真的是太强大了~

KMP算法最浅显理解——一看就明白

AC代码:解法一:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 char text[1005],pattern[1005];//主串,模式串
 5 int perfix[1005],lena,lenb,num;  //prefix数组存放的是最长公共前后缀长度
 6
 7 void KMP()  //KMP匹配字符串算法
 8 {
 9     int i=0,j=-1;//预设j初始化为-1
10     perfix[0]=-1;//prefix[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀
11     while(i<lenb){  //先计算模式串的最长公共前后缀长度,打印前缀表
12         if(j==-1||pattern[i]==pattern[j])perfix[++i]=++j;  //当为-1的时候,文本串和模式串同时i++,j++
13         //j==-1表示若主串的第i个字符和模式的第1个字符不等,应从主串的第i+1个字符开始重新进行匹配
14         else j=perfix[j];  //向右移动模式串
15     }
16     i=j=0;// i是循环主串的指针位置,j是更新模式串当前指针位置,首先将j置为0,将模式串的第一个字符与主串开始比较
17     while(i<lena){    //主串与模式串的匹配
18         if(j==-1||pattern[j]==text[i]){i++;j++;}  //若是j为-1或是主串与模式串当前字符相等,同时i++,j++
19         else j=perfix[j];  //不满足条件,调整模式串的位置,表现为右移
20         if(j==lenb){num++;j=0;}//求不重复的循环次数从0开始(初始值)求重叠式的为 j=perfix[j]
21     }
22 }
23
24 int main()
25 {
26     while(cin>>text){  //a为文本串,b为模式串
27         if(strcmp(text,"#")==0)break;
28         cin>>pattern;
29         num=0,lena=strlen(text),lenb=strlen(pattern);//num是用来计数主串包含多少个模式串
30         KMP();  //KMP算法
31         cout<<num<<endl;
32     }
33     return 0;
34 }

代码过程简单分析:如上所示,我们先对模式串进行打印前缀表,然后再应用KMP算法来与主串匹配。这里给一串模式串abaabcac计算其前缀表。首先我们将前缀表prefix[0]=-1是前导出-1,待循环匹配到i时如果前面没有最长公共前后缀,j==-1加1后变为当前字符串prefix[i]==0,巧妙处理了前缀表。所以给出字符串的前缀表如下:
模式串的下标          0  1  2  3  4  5  6  7

模式串               a  b  a  a  b  c  a  c

前缀表下标         0  1  2  3  4  5  6  7  8

最长前后缀公共长度 -1  0  0  1  1  2  0  1  0

注意上面前缀表与模式串对应的下标位置。计算好模式串的前缀表之后,开始与主串进行匹配了,用i,j分别指向主串,模式串的当前位置,当匹配失败是,指针i(指向主串)不变,指针j(指向模式串)退回到prefix[j]所指示的位置上重新进行比较,并且当指针j退至-1时,指针i和指针j需同时增1。即若主串的第i个字符和模式串的第j个字符不等,应从主串的第i+1个字符重新进行匹配。

上面给的大牛博客里讲的很清楚了,为什么j要退回到prefix[j],这里谈谈我的学习心得:prefix数组记录的是当前字符与前面组成的字符串的最长前后缀公共长度。举个栗子:仍用上面的模式串,假设现在我们要求最后的‘c‘字符下的prefix[8],怎么求呢?已知prefix[7]=1,说明‘c‘字符前面的字符串abaabcac其最长前后缀公共长度为1,这时我们加上字符‘c‘,只需比较最前面的第1个字符‘a‘后面字符‘b‘是否等于当前字符‘c‘,如果相等的话就执行prefix[7+1]=1+1=2(表示最后一个字符下与前面的字符串组成的最大公共前后缀长度是2),否则继续退回,直到-1,显然这里是不等的,所以j会退回-1,这时说明字符‘c‘没办法与第一个字符‘a‘匹配,即prefix[8]=0,退回这个算法很巧妙,不过也在情理之中。接下来进行模式串与主串的匹配,其算法和计算前缀表差不多,多了一步判断j(j是从1开始计算的)是否达到模式串尾,即j==lenb?这样就判断主串是否包含了模式串,同时用num进行计数主串中含有多少个不相交的模式串,OK,满满的收获!

解法2:这道题要求找主串中含有的模式串,那么可以运用库函数strstr()来计数num。

strstr 语法:头文件#include <string.h>

char *strstr( const char *str1, const char *str2 );

功能:函数返回一个指针,它指向字符串str2 首次出现于字符串str1中的位置,如果没有找到,返回NULL。

解题思路:通过这个函数的特点,因为返回的是地址,所以我们定义一个字符指针p来指向接受返回地址,如果找到的话,加上模式串的长度,即接下去寻找是否含有模式串,如果找不到的话,返回NULL将会退出当前循环。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 char text[1005],pattern[1005];//主串,模式串
 4 int main()
 5 {
 6     int len,num;
 7     char *p;
 8     while(cin>>text){
 9         if(strcmp(text,"#")==0)break;
10         cin>>pattern;
11         num=0,len=strlen(pattern);
12         for(p=text;p=strstr(p,pattern);num++,p+=len);
13         cout<<num<<endl;
14     }
15     return 0;
16 }

原文地址:https://www.cnblogs.com/acgoto/p/8727498.html

时间: 2024-08-07 16:35:54

题解报告:hdu 2087 剪花布条(KMP入门)的相关文章

HDU - 2087 剪花布条 (KMP)

Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Input 输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样.花纹条和小饰条不会超过1000个字符长.如果遇见#字符,则不再进行工作. Output 输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间

(KMP 1.3)hdu 2087 剪花布条(求文本串中有几个模式串)

题目: 剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10380    Accepted Submission(s): 6684 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Input 输

HDU 2087 剪花布条【在字符串中不可重叠地寻找子串数量】

一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Input输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样.花纹条和小饰条不会超过1000个字符长.如果遇见#字符,则不再进行工作. Output输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行. Sample In

HDU 2087 剪花布条 KMP入门

Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Input 输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样.花纹条和小饰条不会超过1000个字符长.如果遇见#字符,则不再进行工作. Output 输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出

HDU 2087 剪花布条(模式串在主串中出现的次数主串中子串不可重叠)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题意:求模式串在主串中出现的次数,与模式串匹配的子串之间不可重叠. 思路:用kmp算法解决,在匹配更新结果后,重新定位模式串时,不可用j = next[j],应该直接让j定位到模式串开头. code: 1 #include <cstdio> 2 #include <cstring> 3 4 const int MAXN = 1005; 5 6 char aa[MAXN]; 7 c

HDU 2087 剪花布条 KMP题解

KMP的应用,不过查找的时候注意一点就够了:查找到一个子串的时候,直接跳过整个串,而不是使用next数组前跳,因为根据题意需要剪出小饰条,小饰条之间不能重叠. const int MAX_N = 1001; char txt[MAX_N], pat[MAX_N]; int next[MAX_N], len; void genNext() { for (int i = 1, j = 0; i < len; ) { if (pat[i] == pat[j]) next[i++] = ++j; els

hdu 2087 剪花布条 KMP水题。。

剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10399    Accepted Submission(s): 6701 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Input 输入中含

hdu 2087 剪花布条 kmp模板题

也是kuangbin专题的 专题名字太长 不复制了…… 刚好数据结构也学了kmp 找一道题敲敲模板…… 暴力的字符串匹配是O(n*m)的时间复杂度 而kmp通过一个O(m)的预处理将字符串匹配的时间复杂度降到了O(n+m) kmp的核心是next数组的处理和利用next数组进行字符串匹配 这两个理解了就会用kmp了 1 /* *********************************************** 2 Author :Sun Yuefeng 3 Created Time :

HDU 2087 剪花布条 KMP

题意:找文本串中模式串的个数 解题思路:裸KMP 解题代码: 1 // File Name: getnext.cpp 2 // Author: darkdream 3 // Created Time: 2014年09月09日 星期二 22时35分02秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #include<deque> 10 #includ

(KMP)剪花布条 -- hdu -- 2087

http://acm.hdu.edu.cn/showproblem.php?pid=2087 剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11793    Accepted Submission(s): 7574 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对