HDU 2222 Keywords Search

  第一次写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;

}

 

 

你可能感兴趣的:(search)