SPOJ - WPUZZLES[AC自动机]

首先把所有拼图丢到自动机里面。
然后从边界位置枚举各种可能的方向。
ac自动机的询问就可以判断一下当前节点是否是结尾然后记录答案。

#include<bits/stdc++.h>
using  namespace std;
const int maxn = 1e3+5;
char maze[maxn][maxn];
int len[maxn];
struct node{
	int x, y, dr;
}res[maxn];
int n, m, c;
int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1}; 
int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};
struct AC{
	int nex[maxn*maxn][26], tot, root;
	int f[maxn*maxn], ed[maxn*maxn];
	int newnode() {
		for(int i = 0; i < 26; i++) {
			nex[tot][i] = -1;
		}
		ed[tot] = 0;
		return tot++;
	}
	void init() {
		tot = 0;
		root = newnode();
	}
	void insert(char *s, int x) {
		int u = root;
		for(int i = 0; i < strlen(s); i++) {
			int ch = s[i]-'A';
			if(nex[u][ch] == -1) nex[u][ch] = newnode();
			u = nex[u][ch];
		}
		ed[u] = x;
	}
	void getfail() {
		queue<int>Q;f[root] = root;
		for(int i = 0; i < 26; i++) {
			if(nex[root][i] == -1) nex[root][i] = root;
			else {
				f[nex[root][i]] = root;
				Q.push(nex[root][i]);
			}
		}
		while(!Q.empty()) {
			int u = Q.front();Q.pop();
			for(int i = 0; i < 26; i++) {
				if(nex[u][i] == -1) nex[u][i] = nex[f[u]][i];
				else {
					f[nex[u][i]] = nex[f[u]][i];
					Q.push(nex[u][i]);
				}
			}
		}
	}
	void query(int x, int y, int d) {
		int u = root;
		while(x >= 1 && y >= 1 && x <= n && y <= m) {
			int ch = maze[x][y]-'A';
			u = nex[u][ch];
			if(ed[u]) {
				res[ed[u]].x = x - dx[d]*(len[ed[u]]-1);
				res[ed[u]].y = y - dy[d]*(len[ed[u]]-1);
				res[ed[u]].dr = d;
			}
			x += dx[d];
			y += dy[d];
		}
	}
}ac;
char ss[maxn], s[maxn];
void solve() {
	scanf("%d%d%d", &n ,&m, &c);
	for(int i = 1; i <= n; i++) {
		scanf("%s", maze[i]+1);
	}
	ac.init();
	for(int i = 1; i <= c; i++) {
		scanf("%s", s);
		len[i] = strlen(s);
		ac.insert(s, i);
	}
	ac.getfail();
	for(int i = 1; i <= n; i++) {
		ac.query(i, 1, 1);
		ac.query(i, 1, 2);
		ac.query(i, 1, 3);
	}
	for(int i = 1; i <= m; i++) {
		ac.query(n, i, 0);
		ac.query(n, i, 1);
		ac.query(n, i, 7);
	}
	for(int i = 1; i <= n; i++) {
		ac.query(i, m, 6);
		ac.query(i, m, 7);
		ac.query(i, m, 5);
	}
	for(int i = 1; i <= m; i++) {
		ac.query(1, i, 3);
		ac.query(1, i, 4);
		ac.query(1, i, 5);
	}
	for(int i = 1; i <= c; i++) {
		printf("%d %d %c\n", res[i].x-1, res[i].y-1, res[i].dr+'A');
	}
	puts("");
}
int main() {
	int Case = 1;
	scanf("%d", &Case);
	while(Case--) {
		solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值