题目链接: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; }