IT民工
加油!

  第一次写AC自动机,参考集训手册题解的代码,但是还是花了三个小时的时间才A掉。字符串

插入字典树的过程就是一般字典树形成的过程。这里关键在于求失败指针。有点像KMP求next的过程。

  对于每个结点,我们可以这样处理:设这个结点上的字母为C,沿着他父亲的失败指针走,直到

走到一个结点,他的儿子中也有字母为C的节点。然后把当前结点的失败指针指向那个字母也为C的结

点。如果一直走到了root都没找到,那就把失败指针指向root。最开始,我们把root加入队列(root

的失败指针显然指向自己),这以后我们每处理一个结点,就将他的所有儿子几点入队。

  假设有一个节点k,他的失败指针指向j。那么k,j满足这个性质:设root到j的距离为n,则从k之上

的第n - 1个节点到k所组成的长度为n的单词,与从root之后第一个结点到j所组成的单词相同。

/*Accepted    2222    187MS    26636K    2048 B    G++    Yu*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
using namespace std;
#define init(x) (memset(trie[x], 0, sizeof(trie[x])))
#define next 26
#define root 0
#define cnt 27

const int MAXN = 10001;
const int MAXL = 1000001;
const int MAXM = 28;
int trie[MAXN * 50][MAXM], ntp;
char src[MAXL];
queue<int> q;

void inser(char *s)
{
    int i, cur = root, t;
    for(i = 0; s[i]; i ++)
    {
        t = s[i] - 'a';
        if(!trie[cur][t])
            init(ntp),trie[cur][t] = ntp ++;
        cur = trie[cur][t];
    }
    ++ trie[cur][cnt];
}

void GetNext() //广搜的过程
{
    int cur, t, i;
    q.push(root);
    trie[root][next] = root;
    while(!q.empty())
    {
        cur = q.front(), q.pop();
        for(i = 0; i < 26; i ++)
        {
            if(trie[cur][i])
            {
                if(cur == root) //如果父亲结点是根,那么失败就只能返回根
                    trie[trie[cur][i]][next] = root;
                else
                {
                    t = trie[cur][next]; //trie[cur][i]的父亲cur的失败指针
                    while(t && !trie[t][i]) //找到一个和trie[cur][i]字符相同的结点所处的位置
                        t = trie[t][next];
                    trie[trie[cur][i]][next] = trie[t][i]; //将trie[cur][i]的失败指针指向相同的点
                }
                q.push(trie[cur][i]); //将cur的所有儿子结点入队
            }
            else {
                trie[cur][i] = trie[trie[cur][next]][i]; //不存在这一点,指向父亲结点失败指针的第i个儿子
            }
        }
    }
}

int cal(char *s)
{
    int i, j, cur = root, t, ans = 0;
    for(i = 0; s[i]; i ++)
    {
        t = s[i] - 'a';
        cur = trie[cur][t];
        j = cur;
        while(j && trie[j][cnt] != -1)
        {
            ans += trie[j][cnt];
            trie[j][cnt] = -1;
            j = trie[j][next];
        }
    }
    return ans;
}

int main()
{
    int T, n;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d", &n);
        ntp = 1;
        init(root);
        while(n --)
        {
            scanf("%s", src);
            inser(src);
        }
        GetNext();
        scanf("%s", src);
        printf("%d\n", cal(src));
    }
    return 0;
}

 

 

posted on 2012-08-03 15:32  找回失去的  阅读(209)  评论(0编辑  收藏  举报