poj_1204 Trie图

题目大意

给出一个RxC的字符组成的puzzle,中间可以从左向右,从右到左,从上到下,从下到上,从左上到右下,从右下到左上,从左下到右上,从右上到左下,八个方向进行查找字符串。 
    给出M个字符串,找出他们在puzzle中的位置,返回该字符串在puzzle中的起点横纵坐标以及方向。

字符串长度L <=1000, R,C <= 1000, W <= 1000

题目分析

多模式串的字符串匹配问题,考虑使用Trie图。将M个待查的字符串作为模式串插入Trie图中,然后设置前缀指针,构造DFA。 
    查找的时候,在puzzle的四个边上每个点,沿8个方向分别确定最长的串作为母串,用母串在Trie图上进行行走,进行匹配。

题目比较坑的是,special judge没能对有些正确的结果给AC,只能按照“正常”的顺序来查找。

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<vector>
#include<deque>
using namespace std;
#define MAX_SIZE 1005
#define LETTERS 26
#define MAX_NODES 150000
#define MIN(a, b) a < b? a :b
char gPizza[MAX_SIZE][MAX_SIZE];
struct PosInfo{
	int row;
	int col;
	int dir;
	void SetInfo(int r, int c, int d){
		row = r;
		col = c;
		dir = d;
	}
};
PosInfo gPosInfo[MAX_SIZE];

struct Node{
	Node* childs[LETTERS];
	bool danger_node;
	Node* prev;
	int pattern_index;
	Node(){
		memset(childs, 0, sizeof(childs));
		prev = NULL;
		danger_node = false;
		pattern_index = 0;		//可以指示某个终止节点确定的字符串是第几个pattern
	}
};
Node gNodes[MAX_NODES];
int gNodeCount = 2;

void Insert(Node* root, char* str, int pattern_index){
	Node* node = root;
	char*p = str;
	while (*p != ‘\0‘){
		int index = *p - ‘A‘;
		if (! node->childs[index]){
			node->childs[index] = gNodes + gNodeCount++;
		}
		node = node->childs[index];
		p++;
	}
	node->danger_node = true;
	node->pattern_index = pattern_index;
}

void BuildDfa(){
	Node* root = gNodes + 1;
	for (int i = 0; i < LETTERS; i++){
		gNodes[0].childs[i] = root;
	}
	root->prev = gNodes;
	gNodes[0].prev = NULL;

	deque<Node*> Q;
	Q.push_back(root);
	while (!Q.empty()){
		Node* node = Q.front();
		Node* prev = node->prev, *p;
		Q.pop_front();
		for (int i = 0; i < LETTERS; i++){
			if (node->childs[i]){
				p = prev;
				while (p && !p->childs[i]){
					p = p->prev;
				}
				node->childs[i]->prev = p->childs[i];
				//这个地方注意,不能写成 p->childs[i]->danger_node = node->childs[i]->danger_node
				if (p->childs[i]->danger_node)
					node->childs[i]->danger_node = true;
				Q.push_back(node->childs[i]);
			}
		}
	}
}

bool gPatterFind[MAX_SIZE];
int gPatternFoundNum = 0;
int gMinPatternLen = 0;
int gPatternLen[MAX_SIZE];
int gMoveStep[8][2] = { { -1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, -1 }, {0, -1 }, { -1, -1 } };

//在Trie图上达到一个“危险”节点,则该节点的各个前缀指针,仍然可能为“终止”节点,沿前缀指针找出所有的终止节点,以防止遗漏
//比如 ABCDFF 中查找 ABCD CD 若到达D,确定为一个危险节点,可以找到ABCD,若不沿着前缀指针找出所有的终止节点,则会遗漏CD
void FindPatternFromEndPoint(Node* node, int r, int c, int dir){
	do{
		if (node->pattern_index == 0){
			node = node->prev;
			continue;
		}

		int pattern_index = node->pattern_index;
		if (gPatterFind[pattern_index]){		//此时找到的串,有可能是别的串的前缀,因此继续向后找
			node = node->prev;
			continue;
		}
		gPatterFind[pattern_index] = true;
		gPatternFoundNum++;

		int beg_r = r - gPatternLen[pattern_index] * gMoveStep[dir][0];
		int beg_c = c - gPatternLen[pattern_index] * gMoveStep[dir][1];
		if (gMoveStep[dir][0] == 0)
			beg_r--;

		if (gMoveStep[dir][1] == 0)
			beg_c--;

		if (dir == 1 || dir == 7 || dir == 0){
			beg_r -= 2;
		}
		if (dir == 5 || dir == 7 || dir == 6){
			beg_c -= 2;
		}
		gPosInfo[pattern_index].SetInfo(beg_r, beg_c, dir);

		node = node->prev;
	} while (node);

}
//从某个边界点出发,沿某个方向的最长字符串作为母串,在Trie图上进行查找
void SearchStr(int start_x, int start_y, int dir){
	int r = start_x, c = start_y;
	Node* node = gNodes + 1;
	while (gPizza[r][c] != ‘\0‘){
		int index = gPizza[r][c] - ‘A‘;
		while (node && node->childs[index] == NULL){
			node = node->prev;
		}
		node = node->childs[index];
		if (node->danger_node){
			FindPatternFromEndPoint(node, r, c, dir);
		}
		r += gMoveStep[dir][0];
		c += gMoveStep[dir][1];
	}
}
//确定在边界上的某个点,沿某个方向所构成最长字符串的长度
int MaxLen(int R, int C, int r, int c, int dir){
	if (dir == 0 || dir == 4)
		return R;
	if (dir == 2 || dir == 6)
		return C;
	if (dir == 1){
		if (c == 1)
			return r;
		else if (r == R)
			return C - c + 1;
	}
	if (dir == 5){
		if (r == 1)
			return c;
		else if (c == C)
			return R - r + 1;
	}
	if (dir == 3){
		if (r == 1)
			return C - c + 1;
		if (c == 1)
			return R - r + 1;
	}
	if (dir == 7){
		if (r == R)
			return c;
		if (c == C)
			return r;
	}
	return -1;
}

//对边界上的每个点,在8个方向进行查找
void SearchPuzzle(int R, int C, int total_word_to_find){
	for (int r = 1; r <= R; r++){
		for (int dir = 0; dir < 8; dir++){
			if (gPatternFoundNum == total_word_to_find){
				return;
			}
			if (MaxLen(R, C, r, 1, dir) >= gMinPatternLen){
				SearchStr(r, 1, dir);
			}
		}
	}
	for (int r = 1; r <= R; r++){
		for (int dir = 0; dir < 8; dir++){
			if (gPatternFoundNum == total_word_to_find){
				return;
			}
			if (MaxLen(R, C, r, C, dir) >= gMinPatternLen){
				SearchStr(r, C, dir);
			}
		}
	}
	for (int c = 1; c <= C; c++){
		for (int dir = 0; dir < 8; dir++){
			if (gPatternFoundNum == total_word_to_find){
				return;
			}
			if (MaxLen(R, C, 1, c, dir) >= gMinPatternLen){
				SearchStr(1, c, dir);
			}
		}
	}
	for (int c = 1; c <= C; c++){
		for (int dir = 0; dir < 8; dir++){
			if (gPatternFoundNum == total_word_to_find){
				return;
			}
			if (MaxLen(R, C, R, c, dir) >= gMinPatternLen){
				SearchStr(R, c, dir);
			}
		}
	}
}

int main(){
	int R, C, M;
	scanf("%d %d %d", &R, &C, &M);
	memset(gPizza, 0, sizeof(gPizza));
	memset(gPatterFind, false, sizeof(gPatterFind));
	gNodeCount = 2;

	for (int r = 1; r <= R; r++){
		getchar();
		for (int c = 1; c <= C; c++){
			scanf("%c", &gPizza[r][c]);
		}
	}
	getchar();
	char str[MAX_SIZE];
	Node* root = gNodes + 1;
	for (int i = 1; i <= M; i++){
		scanf("%s", str);
		Insert(root, str, i);
		gPatternLen[i] = strlen(str);
		gMinPatternLen = MIN(gMinPatternLen, gPatternLen[i]);
	}	

	BuildDfa();

	SearchPuzzle(R, C, M);
	for (int i = 1; i <= M; i++){
		printf("%d %d %c\n", gPosInfo[i].row, gPosInfo[i].col, gPosInfo[i].dir + ‘A‘);
	}
	return 0;
}
时间: 2024-10-11 22:57:25

poj_1204 Trie图的相关文章

hiho一下 第二周&amp;第四周:从Trie树到Trie图

hihocoder #1014 题目地址:http://hihocoder.com/problemset/problem/1014 hihocoder #1036 题目地址: http://hihocoder.com/problemset/problem/1036 trie图其实就是trie树+KMP #1014trie树 #include<stdio.h> #include <algorithm> #include <cstring> #include <str

Trie图 &amp; AC自动机初学(1)

题目来源于:Hihocoder 时间限制:20000ms 单点时限:1000ms 内存限制:512MB 描述 前情回顾 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本厚厚的河蟹词典,而他们要做的是判断这篇文章中是否存在那些属于河蟹词典中的词语. 当时,小Hi和小Ho的水平还是十分有限,他们只能够想到:"枚举每一个单词,然后枚举文章中可能的起始位置,然后进行匹配,看能否成功."这样非常朴素的想法,但是这样的算法时间复杂度是

Trie图

DFA 确定性有限状态自动机 DFA确定性有限状态自动机是一种图结构的数据结构,可以由(Q, q0, A, Sigma, Delta)来描述,其中Q为状态集,q0为初始状态,A为终态集合,Sigma为字母表,Delta为转移函数.它表示从唯一一个起始状态q0开始,经过有限步的Delta转移,转移是根据字母表Sigma中的元素来进行,最终到达终态集合A中的某个状态的状态移动.  如图所示是一个终态集合为{"nano"}的DFA.     DFA只能有一个起点而可以有多个终点.每个节点都有

hihoCoder#1036 Trie图

原题地址 看了这篇博文,总算是把Trie图弄明白了 Runtime Error了无数次,一直不知道为什么,于是写了个脚本生成了一组大数据,发现果然段错误了. 调试了一下午,总算闹明白了,为什么呢? 1. 空间超大的变量不要放在函数里,会爆栈,应该弄成全局变量或者是从堆上动态分配. 2. 看清题目的数据范围,一开始我的MAX_NODE设的是1024... 代码: 1 #include <iostream> 2 #include <cstring> 3 4 using namespac

hdu2457 Trie图+dp

hdu2457 给定n个模式串, 和一个文本串 问如果修改最少的字符串使得文本串不包含模式串, 输出最少的次数,如果不能修改成功,则输出-1 dp[i][j] 表示长度为i的字符串, 到达状态j(Trie图中的结点)所需要修改的最少次数 那么dp[0->n][0->size] = INF ,  dp[0][root] = 0,  n代表字符串长度, size代表状态数 那么答案就是  min{dp[n][size]} 我们根据模式串所建的Trie图, 进行模拟构造不包含模式串的字符串 从第一个

【hihoCoder】1036 Trie图

题目:http://hihocoder.com/problemset/problem/1036 给一个词典dict,词典中包含了一些单词words.要求判断给定的一个文本串text中是否包含这个字典中的单词words. 相关基础的理解 1. 与用KMP解决的问题的差别 KMP:输入原串S和一个模式串T,判断T是否出现在S中.通过对T计算next数组,避免原串S的回溯. 现在的问题:输入文本串text和多个单词words,判断words中是否有出现在text中.同样希望输入的text不用进行回溯.

hihocoder 1036 Trie图(AC自动机)

传送门 Description 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本厚厚的河蟹词典,而他们要做的是判断这篇文章中是否存在那些属于河蟹词典中的词语. 当时,小Hi和小Ho的水平还是十分有限,他们只能够想到:“枚举每一个单词,然后枚举文章中可能的起始位置,然后进行匹配,看能否成功.”这样非常朴素的想法,但是这样的算法时间复杂度是相当高的,如果说词典的词语数量为N,每个词语长度为L,文章的长度为M,那么需要进行的计算次数是在N

[hiho 04]Trie图

题目描述 Trie 图就是在 Trie 树上建立 fail 指针,类似于KMP算法中的next数组的作用. 这个数据结构的作用是判断一个字符串中是否包含一组字符串中的任意一个. 结构体定义是这样的: typedef struct trie_node { trie_node *nodes[26]; trie_node *fail = NULL; bool word_end = false; trie_node() { for (int i = 0; i < 26; i++) { nodes[i]

【Trie图】BZOJ3940-[Usaco2015 Feb]Censoring

[题目大意] 有一个匹配串和多个模式串,现在不断删去匹配串中的模式串,求出最后匹配串剩下的部分. [思路] 众所周知,KMP的题往往对应着一道AC自动机quq.本题同BZOJ3942(KMP),这里改成AC自动机即可. 我一开始写了原始的AC自动机,写挂了.后来思考了一下,应当用Trie图,机智地1A. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm&