Poj 1204 Word Puzzles (字符串_AC自动机)

题目链接:http://poj.org/problem?id=1204


题目大意:给定一个n*m的大写字母组成的矩阵,再给定C个单词,这些单词可能出现在矩阵中,出现的方向可能是上、下、左、右、左上、右上、左下、右下,问这C个单词的第一个字母出现在矩阵中的什么位置,以及出现的方向。


解题思路:这题有两种解法,第一种是用字典树+深搜,用单词建立一颗字典树,然后八个方向去深搜,很容易想也很容易写,这种方法在数据很给力的的时候就会超时,所以不多讲。第二种方法是AC自动机,在AC自动机题目中算比较常规的字符串匹配问题。由于要记录每个单词单词在矩阵的第一个字母顺序和方向,这有些困难,因为在匹配的过程中初始没办法回溯求初始位置,硬要这样的话肯定也行,比较麻烦,考虑将单词反转,这样就是最后匹配到的那个位置,这样就不要回溯。建好字典树后改装成AC自动机

,然后在矩阵中从12个方向去查询,如果遇到危险节点(某个单词在这里结束)就可以记录这个单词的位置和方向了。这里并不需要记录12个方向的字符串,只要在查询的过程按照某个方向一直走就好。


测试数据:

20 20 10
QWSPILAATIRAGRAMYKEI
AGTRCLQAXLPOIJLFVBUQ
TQTKAZXVMRWALEMAPKCW
LIEACNKAZXKPOTPIZCEO
FGKLSTCBTROPICALBLBC
JEWHJEEWSMLPOEKORORA
LUPQWRNJOAAGJKMUSJAE
KRQEIOLOAOQPRTVILCBZ
QOPUCAJSPPOUTMTSLPSF
LPOUYTRFGMMLKIUISXSW
WAHCPOIYTGAKLMNAHBVA
EIAKHPLBGSMCLOGNGJML
LDTIKENVCSWQAZUAOEAL
HOPLPGEJKMNUTIIORMNC
LOIUFTGSQACAXMOPBEIO
QOASDHOPEPNBUYUYOBXB
IONIAELOJHSWASMOUTRK
HPOIYTJPLNAQWDRIBITG
LPOINUYMRTEMPTMLMNBO
PAFCOPLHAVAIANALBPFS
MARGARITA
ALEMA
BARBECUE
TROPICAL
SUPREMA
LOUISIANA
CHEESEHAM
EUROPA
HAVAIANA
CAMPONESA


代码:

#include <stdio.h>
#include <string.h>
#define INF 1001

struct node {

	int flag;
	node *fail,*next[26];
}*root,*q[INF*INF],arr[INF*INF];
struct location {
	
	int x,y,dir;
}ans[1001];
int  n,l,w,total,head,tail;
int dir[8][2] = {{-1,0},{-1,1},{0,1},{1,1},
				{1,0},{1,-1},{0,-1},{-1,-1}};	
char str[INF][INF],tp[INF];
char tar[12*INF][INF];

node *new_node(){

	node *p = &arr[total++];
	p->flag = -1;
	p->fail = NULL;
	memset(p->next,NULL,sizeof(p->next));

	return p;
}

void Insert(char *str,int in) {

	node *p = root;
	int i = strlen(str) - 1,k;
	
	for ( ;i >= 0; --i) {

		k = str[i] - 'A';
		if (p->next[k] == NULL) p->next[k] = new_node();
		p = p->next[k];
	}
	p->flag = in;
}

void Ac_automation() {

	node *p = root,*temp;
	root->fail = NULL;
	int i,head = tail = 0;
	q[head++] = root;

	while (tail < head) {

		p = q[tail++];
		for (i = 0; i < 26; ++i) {

			if (p->next[i] != NULL) {

				if (p == root) p->next[i]->fail = root;
				else{
					
					temp = p->fail;
					while (temp != NULL)  {
					
						if (temp->next[i] != NULL) {

							p->next[i]->fail = temp->next[i];
							break;
						}
						temp = temp->fail;
					}
					if (temp == NULL) 
						p->next[i]->fail = root;
				}
				q[head++] = p->next[i];
			}
		}
	}
}

int ifchecked(int x,int y) {

	return x >= 0 && x < n && y >= 0 && y < l;
}

void AC(int xx,int yy,int t) {

	int x = xx,y = yy;
	node *p = root,*temp;

	while (ifchecked(x,y)) {
		
		int k = str[x][y] - 'A';
		while (p->next[k] == NULL && p != root)
			p = p->fail;
		
		p = (p->next[k] != NULL ? p->next[k] : root);
		temp = p;
		while (temp != root) {

			if (temp->flag != -1) {

				ans[temp->flag].x = x;
				ans[temp->flag].y = y;
				ans[temp->flag].dir = t;
				temp->flag = -1;
			}
			temp = temp->fail;
		}
		x += dir[t][0],y += dir[t][1];
	}
}

void Solve_andAC() {

	int i;
	for (i = 0; i < l; ++i) {

		AC(0,i,4),AC(0,i,3),AC(0,i,5);
		AC(n-1,i,1),AC(n-1,i,0),AC(n-1,i,7);
	}
	for (i = 0; i < n; ++i) {

		AC(i,0,1),AC(i,0,2),AC(i,0,3);
		AC(i,l-1,5),AC(i,l-1,6),AC(i,l-1,7);
	}
}

int main()
{
	int i,j,k,t;

	while (scanf("%d%d%d",&n,&l,&w) != EOF) {

		total = 0;
		root = new_node();
		for (i = 0; i < n; ++i)
			scanf("%s",str[i]);

		for (i = 0; i < w; ++i)
			scanf("%s",tp),Insert(tp,i);
		Ac_automation();
		Solve_andAC();

		for (i = 0; i < w; ++i)
			printf("%d %d %c\n",ans[i].x,ans[i].y,(ans[i].dir + 4) % 8 + 'A');
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值