http://poj.org/problem?id=1204
题意:给你一个N*M的由大写字符组成的矩阵,再给你M个长度不超过1000的字符串,要你确定这些字符串在大矩阵中的开始位置和方向。
思路:AC自动机,对匹配串建立Trie树和失败指针,然后就是进行匹配了,所不同的是这里给你模式串不一维的,因此匹配的时候会有一点不同,一开始错误地以为需要对每个点进行8个方向的枚举匹配,这样的复杂度就会达到O(8*N^3) = 8*10^9,这样就会超时,但是后来才发现原来并不需要对每个结点的8个方向都枚举,只只要枚举每个方向的开始的那个点就可以了,这样复杂度就是O(N^2),最多个常数因子,因此就可以解决本题了。另外还有一个技巧就是,因为最后需要输出每个匹配串在模式串中的开始位置, 我们这里可以将匹配串反向建树,就可以很简单地解决这个问题。
代码:
/*
AC自动机
*/
#include<stdio.h>
#include<string.h>
int N , M , Q ;
char map[1010][1010] ;
char str[1010] ;
struct Node{
int f ; //标记是否结束
int num ; //单词的编号
Node *fail ;
Node *next[26] ;
Node(){
fail = 0 ;
f = 0 ;
num = -1 ;
memset(next, 0 , sizeof(next));
}
}*root ;
Node *que[1000010] ;
int front , rear ;
void build_trie(char *ch,int num){
int idx ,len;
Node *loc = root , *q ;
len = strlen(ch);
for(int i=len-1;i>=0;i--){
idx = ch[i] - 'A';
if(loc->next[idx] == NULL){
q = new Node ;
loc->next[idx] = q ;
}
loc = loc->next[idx] ;
}
loc->f = 1 ;
loc->num = num ;
}
void ac_automation(){
Node *loc = root ,*temp;
root->fail = NULL ;
front = rear = 0;
que[rear++] = root ;
while(front < rear){
loc = que[front++] ;
for(int i=0;i<26;i++){
if(loc->next[i] == NULL) continue ;
if(loc == root){
loc->next[i]->fail = root ;
}
else{
temp = loc->fail ;
while(temp != NULL){
if(temp->next[i] != NULL){
loc->next[i]->fail = temp->next[i] ;
break ;
}
temp = temp->fail ;
}
if(temp == NULL){
loc->next[i]->fail = root ;
}
}
que[rear++] = loc->next[i] ;
}
}
}
char part[1010] ;
int dr[8] = {0,1,1,1,0,-1,-1,-1} ;
int dc[8] = {1,1,0,-1,-1,-1,0,1} ;
int ans_r[1010] ;
int ans_c[1010] ;
int ans_dir[1010] ;
bool vis[1010] ;
void query(int row ,int col, int dir){
int i ,j ,idx ;
Node *loc = root ,*q;
int r = row ,c = col ;
int nr , nc ;
for( ; ; ){
idx = map[r][c] - 'A' ;
while(loc!=root && loc->next[idx]==NULL) loc=loc->fail ;
loc = loc->next[idx] ;
if(loc == NULL) loc = root ;
q = loc ;
while(q != root){
if(q->f){
int n = q->num;
if(n!=-1 && vis[n]==0){
ans_r[n] = r ;
ans_c[n] = c ;
ans_dir[n] = dir ;
vis[n] = 1 ;
}
}
q = q->fail ;
}
r += dr[dir] ;
c += dc[dir] ;
if(r<0 || r>=N || c<0 || c>=M) break ;
}
}
char ddd[8] = {'C','D','E','F','G','H','A','B'};
/*
0 : C
1 : D
2 : E
3 : F
4 : G
5 : H
6 : A
7 : B
*/
void solve(){
int i, j ;
for(i=0;i<N;i++){
query(i,0,0);
query(i,M-1,4);
}
for(i=0;i<N;i++){
query(i,0,1);
query(i,M-1,3);
}
for(j=0;j<M;j++){
query(0,j,1);
query(0,j,3);
}
for(j=0;j<M;j++){
query(0,j,2);
query(N-1,j,6);
}
for(i=0;i<N;i++){
query(i,0,7);
query(i,M-1,5);
}
for(j=0;j<M;j++){
query(N-1,j,7);
query(N-1,j,5);
}
for(i = 0;i<Q;i++){
int dd = ( ans_dir[i] + 4 ) % 8 ;
printf("%d %d %c\n",ans_r[i],ans_c[i] ,ddd[dd] );
}
}
int main(){
while(scanf("%d%d%d",&N,&M,&Q) == 3){
for(int i=0;i<N;i++){
scanf("%s",map[i]);
}
root = new Node ;
for(int i=0;i<Q;i++){
scanf("%s",str);
build_trie(str ,i) ;
}
ac_automation() ;
memset(vis , false ,sizeof(vis) );
solve() ;
}
return 0;
}