AC自动机,名字很酷(我就是奔着这名字去的),其实就比字典树多了一个fail指针,什么是fail指针呢,就是串对字典树匹配失配时字典树节点下一步往哪指。是不是和KMP有点像,呵呵,没错,就是KMP的思想,假设该节点是u,它的fail指针指向v,v就是一个和u的字母一样,并且从根出发到v形成的字符串和从根到u的路径上的某一处到u形成的字符串相同的节点。呵呵,有点麻烦,其实求的时候就是一个递推的过程,root的fail指针是NULL,某一个节点u的fail指针就是它的父节点的fail指针指向的节点(以下简称x节点)的u孩子(u孩子就是指一个节点的孩子中的一个和u的字母一样的孩子),如果x没有u孩子,按x的fail指针继续往上找。直到找到,如果找到root仍没有,u的fail指针就指向root。代码可描述为:
struct Trie{ int count; struct Trie *fail; struct Trie *next[26]; } *root,*queue[500005]; void get_fail() { int start = 0,end = 1,i; struct Trie *p = root,*q; root->fail = NULL; root->count = -1; queue[start] = p; while (start < end){ p = queue[start]; for (i = 0; i< 26; i++){ if (p->next[i] != NULL){ queue[end++] = p->next[i]; q = p; while (q->fail != NULL){ if (q->fail->next[i] != NULL){ p->next[i]->fail = q->fail->next[i]; break; } else q = q->fail; } if (q->fail == NULL) p->next[i]->fail = root; } } start++; } }
至于匹配,和KMP差不多啦,代码为
void search(int x,int y,int k) { int x1 = x,y1 = y; struct Trie *p = root,*q; while (x1 >= 0 && y1 >= 0 && x1 < n && y1 < m){ int id = map[x1][y1] - 'A'; while (p->next[id] == NULL && p->fail != NULL) p = p->fail; p = p->next[id]; p = (p == NULL)?root:p; q = p; while (q != root && q->count != -1){ result[q->count][0] = x1-lenth[q->count]*dir[k][0]; result[q->count][1] = y1-lenth[q->count]*dir[k][1]; ans[q->count] = k + 'A'; q->count = -1; q = q->fail; } x1 += dir[k][0]; y1 += dir[k][1]; } }
至于题,下次发吧!下午还有万恶的比赛。。。。