AC自动机的灵活运用,本题关键是灵活二字。
因为数据不是很大,时间要求也不高的缘故,所以本题有人使用暴力法也过了,有人使用Trie也过了。
当然有人使用AC自动机没AC的,在讨论区里喊AC自动机超时的,那是因为不会灵活运用,或者是硬套模板的,AC了速度也不会快。
给出本人的算法思路:
1 把需要查找的关键字建立Trie, 然后构造AC自动机
2 查找的时候分八个方向查找,比如棋盘是board[N][M],那么就可以循环i(0->N-1),然后每次把board[i]当做一个文本,做过HDU的key word那道题目的人都知道如何搜索一个文本中有多少关键字出现,这样不就把本题转换为查找文本关键字的问题了。 不过本题是需要八个方向的八个文本都搜索一遍,八是个不大的常数。其他方向如何构造一个文本,就可以自己思考一下,不难。
3 记录结果就看个人的编程能力了,这里的技巧是逆转关键字建立Trie,那么搜索到尾就是每个关键字的开头了。
AC自动机虽然高级,但是也还是一个算法工具,套模板,一大抄的代码没什么意义的,还是彻底消化掉,然后灵活运用才是关键。
对于本题写出高效的算法,那么是超过5星级难度的。
下面给出个上面思路的实现算法,速度很快的。
出处: http://blog.csdn.net/kenden23
#include <stdio.h> #include <string.h> #include <queue> using std::queue; const int MAX_LEN = 1001; const int ARR_SIZE = 26; char board[MAX_LEN][MAX_LEN]; char word[MAX_LEN], gDir[MAX_LEN]; int gIndices[MAX_LEN][2]; int L, C, W; inline int getIndex(char ch) { return ch-'A'; } struct Node { int n, index; Node *fail; Node *arr[ARR_SIZE]; }; void clearNode(Node *p) { p->n = 0; p->index = 0; p->fail = NULL; for (int i = 0; i < ARR_SIZE; i++) { p->arr[i] = NULL; } } Node gPool[MAX_LEN*MAX_LEN]; int gPoolId; Node *Trie; void insertTrie(char w[], int index) { Node *pCrawl = Trie; int len = strlen(w); for (int i = len-1; i >= 0; i--)//逆向插入字符串,方便找到起头节点 { int id = getIndex(w[i]); if (!pCrawl->arr[id]) { pCrawl->arr[id] = &gPool[gPoolId++]; clearNode(pCrawl->arr[id]); } pCrawl = pCrawl->arr[id]; } pCrawl->n++; pCrawl->index = index; } void buildFail() { queue<Node *> qu; qu.push(Trie); while (!qu.empty()) { Node *pCrawl = qu.front(); qu.pop(); for (int i = 0; i < ARR_SIZE; i++) { if (!pCrawl->arr[i]) continue; pCrawl->arr[i]->fail = Trie; Node *fail = pCrawl->fail; while (fail) { if (fail->arr[i]) { pCrawl->arr[i]->fail = fail->arr[i]; break; } fail = fail->fail; } qu.push(pCrawl->arr[i]); } } } void searchDirect(int r, int c, int rDir, int cDir, char dir) { Node *pCrawl = Trie; while (0<=r && 0<=c && r < L && c < C) { int id = getIndex(board[r][c]); while (!pCrawl->arr[id] && pCrawl != Trie) pCrawl = pCrawl->fail; if (pCrawl->arr[id]) { pCrawl = pCrawl->arr[id]; Node *tmp = pCrawl; while (tmp && tmp->n != -1) { if (tmp->n)//record results { gIndices[tmp->index][0] = r; gIndices[tmp->index][1] = c; gDir[tmp->index] = dir; } tmp->n = -1; tmp = tmp->fail; } } r += rDir, c += cDir; //Watch out, if we use "continue"! } } void searchAll() { char dir = 'E', counterDir = 'A'; for (int c = 0; c < C; c++) { searchDirect(L-1, c, -1, 0, dir); searchDirect(0, c, 1, 0, counterDir); } dir = 'G', counterDir = 'C'; for (int r = 0; r < L; r++) { searchDirect(r, 0, 0, 1, dir); searchDirect(r, C-1, 0, -1, counterDir); } dir = 'H', counterDir = 'D'; for (int c = 0; c < C; c++) { searchDirect(0, c, 1, 1, dir); searchDirect(L-1, c, -1, -1, counterDir); } for (int r = 1; r < L; r++) { searchDirect(r, 0, 1, 1, dir); searchDirect(r, C-1, -1, -1, counterDir); } dir = 'F', counterDir = 'B'; for (int c = 0; c < C; c++) { searchDirect(L-1, c, -1, 1, dir); searchDirect(0, c, 1, -1, counterDir); } for (int r = 0; r < L; r++) { searchDirect(r, 0, -1, 1, dir); searchDirect(r, C-1, 1, -1, counterDir); } } int main() { Trie = &gPool[0]; while (scanf("%d %d %d", &L, &C, &W) != EOF) { clearNode(Trie); gPoolId = 1; getchar(); for (int i = 0; i < L; i++) { gets(board[i]); } for (int i = 0; i < W; i++) { gets(word); insertTrie(word, i); } buildFail(); searchAll(); for (int i = 0; i < W; i++) { printf("%d %d %c\n", gIndices[i][0], gIndices[i][1], gDir[i]); } } return 0; }
POJ 1204 Word Puzzles AC自动机题解
时间: 2024-10-09 03:01:29