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; }