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原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(c,struct,测试,null,insert)