POJ 1204 AC自动机

链接:

http://poj.org/problem?id=1204

题意:

给定一个n*m的大写字母组成的矩阵,再给定C个单词,这些单词可能出现在矩阵中,出现的方向可能是上、下、左、右、左上、右上、左下、右下

问这C个单词的第一个字母出现在矩阵中的什么位置,以及出现的方向。

题解:

这题有两种解法,第一种是用字典树+深搜,用单词建立一颗字典树,然后八个方向去深搜,很容易想也很容易写,这种方法在数据很给力的的时候就会超时,所以不多讲。

第二种方法是AC自动机,在AC自动机题目中算比较常规的字符串匹配问题。

由于要记录每个单词单词在矩阵的第一个字母顺序和方向,这有些困难,因为在匹配的过程中初始没办法回溯求初始位置,硬要这样的话肯定也行,比较麻烦。

考虑将单词反转,这样就是最后匹配到的那个位置,这样就不要回溯。

建好字典树后改装成AC自动机,然后在矩阵中从12个方向去查询,如果遇到危险节点(某个单词在这里结束)就可以记录这个单词的位置和方向了。

这里并不需要记录12个方向的字符串,只要在查询的过程按照某个方向一直走就好。

代码:

 31 int n, m, w;
 32 string s[MAXN];
 33 int pos[MAXN][3];
 34 int dir[8][2] = { 0,1,0,-1,1,0,-1,0,1,1,-1,-1,1,-1,-1,1 };
 35 char ch[9] = "CGEADHFB";
 36 int head, tail;
 37 
 38 struct node {
 39     node *fail;
 40     node *next[26];
 41     int id;
 42     node() {
 43         fail = NULL;
 44         id= 0;
 45         rep(i, 0, 26) next[i] = NULL;
 46     }
 47 }*q[1000010];
 48 node *root;
 49 
 50 void insert(string s, int id) {
 51     node *p = root;
 52     int len = s.length();
 53     rep(i, 0, len) {
 54         int temp = s[i] - 'A';
 55         if (p->next[temp] == NULL) p->next[temp] = new node();
 56         p = p->next[temp];
 57     }
 58     p->id = id;
 59 }
 60 
 61 void build_ac() {
 62     q[tail++] = root;
 63     while (head != tail) {
 64         node *p = q[head++];
 65         node *temp = NULL;
 66         rep(i, 0, 26) if (p->next[i] != NULL) {
 67             if (p == root) p->next[i]->fail = root;
 68             else {
 69                 temp = p->fail;
 70                 while (temp != NULL) {
 71                     if (temp->next[i] != NULL) {
 72                         p->next[i]->fail = temp->next[i];
 73                         break;
 74                     }
 75                     temp = temp->fail;
 76                 }
 77                 if (temp == NULL) p->next[i]->fail = root;
 78             }
 79             q[tail++] = p->next[i];
 80         }
 81     }
 82 }
 83 
 84 void query(int x, int y, int d, int id) {
 85     node *p = root;
 86     while (x >= 0 && x < n && y >= 0 && y < m) {
 87         int index = s[x][y] - 'A';
 88         while (p->next[index] == NULL && p != root) p = p->fail;
 89         p = p->next[index];
 90         if (p == NULL) p = root;
 91         node *temp = p;
 92         while (temp != root && temp->id) {
 93             int k = temp->id;
 94             if (pos[k][0] > x || pos[k][0] == x && pos[k][1] > y)
 95                 pos[k][0] = x, pos[k][1] = y, pos[k][2] = id;
 96             temp = temp->fail;
 97         }
 98         x += dir[d][0];
 99         y += dir[d][1];
100     }
101 }
102 
103 int main() {
104     ios::sync_with_stdio(false), cin.tie(0);
105     cin >> n >> m >> w;
106     root = new node(); 
107     rep(i, 0, n) cin >> s[i];
108     rep(i, 1, w + 1) {
109         string a;
110         cin >> a;
111         reverse(all(a));
112         insert(a, i);
113         pos[i][0] = pos[i][1] = INF;
114     }
115     build_ac();
116     rep(i, 0, n) {
117         query(i, 0, 0, 1), query(i, m - 1, 1, 0);
118         query(i, 0, 7, 6), query(i, m - 1, 6, 7);
119         query(i, 0, 4, 5), query(i, m - 1, 5, 4);
120     }
121     rep(i, 0, m) {
122         query(0, i, 2, 3), query(n - 1, i, 3, 2);
123         query(0, i, 6, 7), query(n - 1, i, 7, 6);
124         query(0, i, 4, 5), query(n - 1, i, 5, 4);
125     }
126     rep(i, 1, w + 1)
127         cout << pos[i][0] << ' ' << pos[i][1] << ' ' << ch[pos[i][2]] << endl;
128     return 0;
129 }

 

posted @ 2017-05-01 22:01  Flowersea  阅读(274)  评论(7编辑  收藏  举报