【POJ 3461】Oulipo 中文题意&题解&代码(C++)
2016-02-16 20:23
519 查看
**
Time Limit: 1000MS Memory Limit: 65536K
Description
The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter ‘e’. He was a member of the Oulipo group. A quote from the book:
Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…
Perec would probably have scored high (or rather, low) in the following contest. People are asked to write a perhaps even meaningful text on some subject with as few occurrences of a given “word” as possible. Our task is to provide the jury with a program that counts these occurrences, in order to obtain a ranking of the competitors. These competitors often write very long texts with nonsense meaning; a sequence of 500,000 consecutive ‘T’s is not unusual. And they never use spaces.
So we want to quickly find out how often a word, i.e., a given string, occurs in a text. More formally: given the alphabet {‘A’, ‘B’, ‘C’, …, ‘Z’} and two finite strings over that alphabet, a word W and a text T, count the number of occurrences of W in T. All the consecutive characters of W must exactly match consecutive characters of T. Occurrences may overlap.
Input
The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:
One line with the word W, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W).
One line with the text T, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with |W| ≤ |T| ≤ 1,000,000.
Output
For every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T.
Sample Input
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
Sample Output
1
3
0
中文题意:
简单说,就是给你n组数据,每组数据中包含两个字符串s和t,找出字符串s在字符串t中出现的次数,例:ababa中字符串aba出现2次,输出2。
题解:
了解kmp之后可以一眼就看出这是一道kmp的模板题,这里谈一下kmp算法的个人理解。
kmp算法是一种用于两个字符串直接匹配的效率较高的算法,它的核心思想是构造一个fail指针(本文中建立一个nex数组来表示),当字符串匹配到某一位失败时,就找到指针所指的地方开始重新匹配,而不是重头开始匹配。
举例: 要在 a b a c a a b a c a b a c a b a a b b 中匹配 a b a c a b。
假设将 a b a c a a b a c a b a c a b a a b b 称为串 s
……. 将 a b a c a b 称为串 t
复杂的nm算法就是暴力枚举如下:
我们可以看到这个算法的实质是首先将串 s 和 串 t 的第一位对齐进行匹配,若匹配成功则不再继续匹配,若匹配失败则将串 s 的下一位和串 t 的第一位对齐匹配,直到无法再匹配,这样的复杂度是很高的,至少本题这么做肯定是过不了。
那么该怎么办呢,是什么地方浪费了复杂度呢,以上述字符串为例,首先将两个字符串对齐,当第一次匹配到 t[5] 时发现匹配失败,此时我们发现如果直接将串 t 向右移一位匹配时,因为我们的for循环已经扫过了串s的前几位,发现这些地方不可能再和串t成功匹配,向右一位一位的移完全是浪费时间,我们完全可以直接将字符串 t[0] 向右平移到 s[5] 的位置进行匹配才有可能得到有效的答案,然而我们要怎样才能实现这样的操作呢,这里就要引入一个 nex[] 数组,即上文提到的fail指针。
nex[i]表示串 t 的 t[0]~t[ nex[i] ] 与串t的 t [ i - nex[i] ]~ t [ i ] 都相同
在本题中
那么这个 nex[] 数组该怎么求得呢,附代码解释:
很抱歉..博主本人写到这里已经快崩溃了QAQ,看来kmp的思想还是没有完全理解透,就不强行装x了,等真正理解了再继续写,所以大家还是去看别的大神的解释吧…orz
但是代码还是得附的,大家自己意会吧……
求nex是kmp的核心部分,当你理解了求nex的部分后下面的部分也就很容易看懂了
kmp:
这道题的代码:
感觉对那些写出来kmp算法详解的大神都好牛,虽然看他们写的我并不能看太懂,但是好歹也写出来了QAQ,看来水平真的很渣啊…
Oulipo
**Time Limit: 1000MS Memory Limit: 65536K
Description
The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter ‘e’. He was a member of the Oulipo group. A quote from the book:
Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…
Perec would probably have scored high (or rather, low) in the following contest. People are asked to write a perhaps even meaningful text on some subject with as few occurrences of a given “word” as possible. Our task is to provide the jury with a program that counts these occurrences, in order to obtain a ranking of the competitors. These competitors often write very long texts with nonsense meaning; a sequence of 500,000 consecutive ‘T’s is not unusual. And they never use spaces.
So we want to quickly find out how often a word, i.e., a given string, occurs in a text. More formally: given the alphabet {‘A’, ‘B’, ‘C’, …, ‘Z’} and two finite strings over that alphabet, a word W and a text T, count the number of occurrences of W in T. All the consecutive characters of W must exactly match consecutive characters of T. Occurrences may overlap.
Input
The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:
One line with the word W, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W).
One line with the text T, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with |W| ≤ |T| ≤ 1,000,000.
Output
For every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T.
Sample Input
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
Sample Output
1
3
0
中文题意:
简单说,就是给你n组数据,每组数据中包含两个字符串s和t,找出字符串s在字符串t中出现的次数,例:ababa中字符串aba出现2次,输出2。
题解:
了解kmp之后可以一眼就看出这是一道kmp的模板题,这里谈一下kmp算法的个人理解。
kmp算法是一种用于两个字符串直接匹配的效率较高的算法,它的核心思想是构造一个fail指针(本文中建立一个nex数组来表示),当字符串匹配到某一位失败时,就找到指针所指的地方开始重新匹配,而不是重头开始匹配。
举例: 要在 a b a c a a b a c a b a c a b a a b b 中匹配 a b a c a b。
假设将 a b a c a a b a c a b a c a b a a b b 称为串 s
……. 将 a b a c a b 称为串 t
a b a c a a b a c a b a c a b a a b b a b a c a b 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 a b a c a a b a c a b a c a b a a b b a b a c a b
复杂的nm算法就是暴力枚举如下:
for (int i=0;i<s.size();i++) { int now=i,j=0; while(s[now]==t[j] && j<=t.size()) j++,now++; if (j==t.size()) cout<<"YES"<<endl,break; }
我们可以看到这个算法的实质是首先将串 s 和 串 t 的第一位对齐进行匹配,若匹配成功则不再继续匹配,若匹配失败则将串 s 的下一位和串 t 的第一位对齐匹配,直到无法再匹配,这样的复杂度是很高的,至少本题这么做肯定是过不了。
那么该怎么办呢,是什么地方浪费了复杂度呢,以上述字符串为例,首先将两个字符串对齐,当第一次匹配到 t[5] 时发现匹配失败,此时我们发现如果直接将串 t 向右移一位匹配时,因为我们的for循环已经扫过了串s的前几位,发现这些地方不可能再和串t成功匹配,向右一位一位的移完全是浪费时间,我们完全可以直接将字符串 t[0] 向右平移到 s[5] 的位置进行匹配才有可能得到有效的答案,然而我们要怎样才能实现这样的操作呢,这里就要引入一个 nex[] 数组,即上文提到的fail指针。
nex[i]表示串 t 的 t[0]~t[ nex[i] ] 与串t的 t [ i - nex[i] ]~ t [ i ] 都相同
在本题中
0 1 2 3 4 5 t a b a c a b nex -1 -1 0 -1 0 1
那么这个 nex[] 数组该怎么求得呢,附代码解释:
很抱歉..博主本人写到这里已经快崩溃了QAQ,看来kmp的思想还是没有完全理解透,就不强行装x了,等真正理解了再继续写,所以大家还是去看别的大神的解释吧…orz
但是代码还是得附的,大家自己意会吧……
inline void getnex() { int j=-1; for (int i=0;i<lent;i++) { while(t[i]!=t[j+1] && j!=-1) j=nex[j]; if (t[i]==t[j+1] && i!=0) j++; nex[i]=j; } }
求nex是kmp的核心部分,当你理解了求nex的部分后下面的部分也就很容易看懂了
kmp:
inline void kmp() { int j=-1; for (int i=0;i<lens;i++) { while(s[i]!=t[j+1] && j!=-1) j=nex[j]; if (s[i]==t[j+1]) j++; if (j==lent-1) ans++,j=nex[j]; } }
这道题的代码:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
char s[1000005],t[10005];//
int nex[10005],ans,n,lens,lent;
inline void getnex() { int j=-1; for (int i=0;i<lent;i++) { while(t[i]!=t[j+1] && j!=-1) j=nex[j]; if (t[i]==t[j+1] && i!=0) j++; nex[i]=j; } }
inline void kmp() { int j=-1; for (int i=0;i<lens;i++) { while(s[i]!=t[j+1] && j!=-1) j=nex[j]; if (s[i]==t[j+1]) j++; if (j==lent-1) ans++,j=nex[j]; } }
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
ans=0;
scanf("%s %s",t,s);
lens=strlen(s);
lent=strlen(t);
getnex();
kmp();
printf("%d\n",ans);
}
}
感觉对那些写出来kmp算法详解的大神都好牛,虽然看他们写的我并不能看太懂,但是好歹也写出来了QAQ,看来水平真的很渣啊…
相关文章推荐
- 【C++】顺时针打印矩阵
- 20160201.CCPP体系详解(0011天)
- 20160131.CCPP体系详解(0010天)
- bzoj 3238 差异
- 20160130.CCPP体系详解(0009天)
- 二叉树层次遍历(C语言实现)
- 面向对象课程 - 寒假第三次作业 - C++计算器项目初始部分
- c++參数传递
- C语言-内存对齐
- C++STL-全排列
- C++中指针和引用的区别
- C语言语法
- C语言:IF-ELSE的配对问题
- Effective C++ 06:若不想使用编译器自动生成的函数,就该明确拒绝
- C++ 返回值优化
- vim ctags omnicppcomplete 无法自动提示成员变量,总是提示“找不到模式”的解决方法
- 今年业余时间要完成C++与数据库的对接
- ios开发中的C语言学习—— 结构体简介
- 现代JVM内存管理方法及GC的实现和主要思路
- 《API Design for C++》读书笔记(二):API特征