题目链接:http://poj.org/problem?id=1204
题意:给出一个字符方阵和一系列字符串,试从方阵中找出字符串出现的位置,方阵中字符串按八个方向查询。
将待查询字符串插入字典树,构造AC自动机,然后对方阵的四条边,每条边对应的三个方向进行查询。
Code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define M 1024
typedef struct{
int x,y,d;
}Result;
typedef struct talT{
int k;
talT *fail,*nxt[26];
}Trie;
int dir[][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
Result res[M];
char s[M][M];
char tmp[M];
int size;
Trie Memory[M<<8];
Trie *q[M<<8];
Trie *r;
int len[M];
int head,tail;
int l,c,w;
Trie *NewTrie()
{
return &Memory[size++];
}
int Legal(int x,int y)
{
if(x<0||x>=l) return 0;
if(y<0||y>=c) return 0;
return 1;
}
void Insert(char *p,int k)
{
Trie *cur=r;
int a;
while(*p){
a=*p++-'A';
if(!cur->nxt[a])
cur->nxt[a]=NewTrie();
cur=cur->nxt[a];
}
cur->k=k;
}
void ACAutomation()
{
Trie *cur,*pre;
int i;
head=tail=0;
r->fail=NULL;
q[tail++]=r;
while(head^tail){
cur=q[head++];
for(i=0;i<26;i++){
if(!cur->nxt[i]) continue;
if(cur==r)
cur->nxt[i]->fail=r;
else{
pre=cur->fail;
while(pre&&!pre->nxt[i])
pre=pre->fail;
cur->nxt[i]->fail=pre?pre->nxt[i]:r;
}
q[tail++]=cur->nxt[i];
}
}
}
void ACRun(int x,int y,int d)
{
int a;
Trie *tmp,*cur=r;
for(;Legal(x,y);x+=dir[d][0],y+=dir[d][1]){
a=s[x][y]-'A';
while(!cur->nxt[a]&&cur!=r)
cur=cur->fail;
cur=cur->nxt[a];
if(cur==NULL) cur=r;
tmp=cur;
while(tmp!=r&&tmp->k){
res[tmp->k].x=x-dir[d][0]*(len[tmp->k]-1);
res[tmp->k].y=y-dir[d][1]*(len[tmp->k]-1);
res[tmp->k].d=d;
tmp->k=0;
tmp=tmp->fail;
}
}
}
void ACWork()
{
int i;
for(i=0;i<c;i++){
ACRun(0,i,3);ACRun(0,i,4);ACRun(0,i,5);
ACRun(c-1,i,0);ACRun(c-1,i,1);ACRun(c-1,i,7);
}
for(i=0;i<l;i++){
ACRun(i,0,1);ACRun(i,0,2);ACRun(i,0,3);
ACRun(i,c-1,5);ACRun(i,c-1,6);ACRun(i,c-1,7);
}
}
int main()
{
int i;
scanf("%d%d%d",&l,&c,&w);
for(i=0;i<l;i++)
scanf("%s",s[i]);
r=NewTrie();
for(i=1;i<=w;i++){
scanf("%s",tmp);
len[i]=strlen(tmp);
Insert(tmp,i);
}
ACAutomation();
ACWork();
for(i=1;i<=w;i++)
printf("%d %d %c\n",res[i].x,res[i].y,res[i].d+'A');
return 0;
}