POJ 3461 Oulipo

题目大意:

        法国的一位作家乔治·佩雷克曾写过一本书《失踪者》,整本书里没有一个含字母e的单词,他也是Oulipo组织的成员。

        佩雷克经常参加一种比赛并得高分,比赛内容是写一篇有指定主题的文章,文章里不能含给定的单词,而我们需要提供一种裁判程序,判定选手在文章中出现过指定单词多少次并记分。

        现有多个测例(测例数题中给出),每个测例中都给出指定一个单词W(不含空格,长度为[1, 10000])和一篇文章(长度为[|W|, 1000000]),这些字符串都是建立在大写字母表上的,对于每个测例都输出单词在文章中出现的次数。

题目链接

注释代码:

/*   
 * Problem ID : POJ 3461 Oulipo 
 * Author     : Lirx.t.Una   
 * Language   : G++   
 * Run Time   : 94 ms   
 * Run Memory : 1404 KB   
*/

#pragma G++ optimize("O2")

#include <string.h>
#include <stdio.h>

//maximum word length
//单词的最大长度
//由于是从下标1开始存放的因此需要+2
#define	MAXWDLEN		10002
//maximum text length
//文章的最大长度
//同理+2
#define	MAXTXTLEN		1000002

char	w[MAXWDLEN];//word,存放单词
//next数组
//next[i]表示字符串w[1-i]的一个最长前缀
//这个最长前缀等于该字符串的一个后缀
//比如字符串1235123中w[7]=3(即最后一个字符)
//而next[7]=3,w[3]=3
//这里next[7]得到的是一个下标3,通过该下表得到字符3
//注意,以下标3为结尾的字符串123就是w[7]的最长前缀
//前缀123和后缀123完全相等
int		nxt[MAXWDLEN];
char	t[MAXTXTLEN];//text,存放文章

void
bd_nxt(int len) {//build next
	//构造next数组
	//其构造方法和kmp算法相同
	//只是主串和模式串都是w自己而已
	//len为w的长度

	int		i, j;//i为主串指针,j为模式串的匹配指针
	//算法运作是i不断向前
	//j根据是否能和i指向的字符匹配而利用next数组回退

	nxt[1] = 0;//首字符无法回溯,只能回退会0
	//由于next数组还未构造,因此只能从头开始构造
	//后面的利用前面的
	//是一种动态规划的思想
	for ( j = 0, i = 2; i <= len; i++ ) {//j初始化为0,表示还未进行匹配
		//i由于1已经初始化过了,因此从2开始算起
	
		while ( j > 0 && w[j + 1] != w[i] )//如果j不指向空且j + 1不能能和i匹配
			j = nxt[j];//就回退

		if ( w[j + 1] == w[i] )//当j为空或者j + 1能匹配上了则j跟随i请进
			j++;

		nxt[i] = j;//赋值
	}
}

int
kmp( int wlen, int tlen ) {//KMP算法
	//两个参数分别为w长度和t的长度

	int		i, j;//主、模指针
	int		cnt;//count,记录w在t中出现的次数

	bd_nxt(wlen);//先构造next数组

	for ( cnt = 0, j = 0, i = 1; i <= tlen; i++ ) {
	
		while ( j > 0 && w[j + 1] != t[i] )
			j = nxt[j];

		if ( w[j + 1] == t[i] )
			j++;

		if ( j == wlen ) {//注意:当w完全匹配上了以后
		
			cnt++;//不仅计数++
			j = nxt[j];//并且j需要回退,因为w可能存在前缀和后缀重叠的两个部分
		}
	}

	return cnt;
}

int
main() {

	int		nscn;

	scanf("%d", &nscn);
	while ( nscn-- ) {
	
		scanf("%s%s", w + 1, t + 1);
		printf("%d\n", kmp( strlen(w + 1), strlen(t + 1) ));
	}

	return 0;
}

无注释代码:

#pragma G++ optimize("O2")

#include <string.h>
#include <stdio.h>

#define	MAXWDLEN		10002
#define	MAXTXTLEN		1000002

char	w[MAXWDLEN];
int		nxt[MAXWDLEN];
char	t[MAXTXTLEN];

void
bd_nxt(int len) {

	int		i, j;

	nxt[1] = 0;
	for ( j = 0, i = 2; i <= len; i++ ) {
	
		while ( j > 0 && w[j + 1] != w[i] )
			j = nxt[j];

		if ( w[j + 1] == w[i] )
			j++;

		nxt[i] = j;
	}
}

int
kmp( int wlen, int tlen ) {

	int		i, j;
	int		cnt;

	bd_nxt(wlen);

	for ( cnt = 0, j = 0, i = 1; i <= tlen; i++ ) {
	
		while ( j > 0 && w[j + 1] != t[i] )
			j = nxt[j];

		if ( w[j + 1] == t[i] )
			j++;

		if ( j == wlen ) {
		
			cnt++;
			j = nxt[j];
		}
	}

	return cnt;
}

int
main() {

	int		nscn;

	scanf("%d", &nscn);
	while ( nscn-- ) {
	
		scanf("%s%s", w + 1, t + 1);
		printf("%d\n", kmp( strlen(w + 1), strlen(t + 1) ));
	}

	return 0;
}

单词解释:

Oulipo:一个法国的作家以及数学家组织

Perec:人名,佩雷克(法国作家)

La disparition:佩雷克小说《失踪者》

or rather:更精确地说,倒不如说

subject:n, 主题

occurrence:n, 出现,发生

jury:n, 陪审团,评判委员会

ranking:n, 等级,地位,排名

competitor:n, 竞争者,对手

nonsense:n, 胡说,废话

formally:adv, 正式地,形式地

alphabet:n, 字母表

finite:adj, 有限的

overlap:vt/vi, 重叠

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值