POJ 1204-Word Puzzles
POJ 1204-Word Puzzles
题意
给出一个n*m的字母表,t个字符串,要求找到这t个字符串的首字母出现位置即字符串的方向(总共A-H八个方向,A表示向上,B表示向右上,逆时针依次表示)
题解
将t个字符串构建AC自动机,然后枚举开始搜索的起点和方向。
注
tr[N][26]开大一点
代码
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=1e6+10;
const int M=1e3+10;
int tr[N][26],tot;
int e[N],fail[N],len[N];
queue<int> q;
char s[N];
int n,m,t;
char graph[M][M];
struct node{
	int x,y,z;
}ans[N];
const int dx[8]={0,1,0,-1,1,1,-1,-1};
const int dy[8]={1,0,-1,0,-1,1,1,-1};
const char dir[8]={'C','E','G','A','F','D','B','H'};
void insert(int k){
	int u=0;
	for(int i=0;i<len[k];i++){
		int ch=s[i]-'A';
		if(!tr[u][ch]) tr[u][ch]=++tot;
		u=tr[u][ch];
	}
	//标记第k个字符串的尾节点 
	e[u]=k;
} 
void build(){
	for(int i=0;i<26;i++){
		if(tr[0][i]) q.push(tr[0][i]);
	}
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(tr[u][i]){
				fail[tr[u][i]]=tr[fail[u]][i];
				q.push(tr[u][i]);
			}else tr[u][i]=tr[fail[u]][i];
		}
	}
}
//传入开始搜索的坐标(x,y)和搜索方向 
void check(int x,int y,int d){
	int u=0;
	while(x>=0&&x<n&&y>=0&&y<m){
		int ch=graph[x][y]-'A';
		u=tr[u][ch];
		for(int j=u;j&&e[j]!=-1;j=fail[j]){
			//如果是某个字符串的尾节点 
			if(e[j]){
				int idx=e[j];
				int l=len[idx];
				ans[idx].x=x-(l-1)*dx[d];
				ans[idx].y=y-(l-1)*dy[d];
				ans[idx].z=d;
				e[j]=-1;
			}
		}
		x+=dx[d];
		y+=dy[d];
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&t);
	for(int i=0;i<n;i++) scanf("%s",graph[i]);
	for(int i=1;i<=t;i++){
		scanf("%s",s);
		int l=strlen(s);
		len[i]=l;
		insert(i);
	}
	build();
	for(int i=0;i<n;i++)
    	for(int j=0;j<8;j++)
        	check(i,0,j);
    for(int i=n-1;i>=0;i--)
    	for(int j=0;j<8;j++)
        	check(i,n-1,j);
    for(int i=m-1;i>=0;i--)
    	for(int j=0;j<8;j++)
        	check(0,i,j);
    for(int i=0;i<m;i++)
    	for(int j=0;j<8;j++)
        	check(n-1,i,j);
	for(int i=1;i<=t;i++){
		printf("%d %d %c\n",ans[i].x,ans[i].y,dir[ans[i].z]);
	}
	return 0;
}
 
    
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号