Keywords Search

题目大意:输入几个子串,然后输入一个母串,问在母串里面包含几个子串。
 
分析:刚学习的AC自动机,据说这是个最基础的模板题,所以也是用了最基本的写法来完成的,当然也借鉴了别人的代码思想,确实是个很神奇的东西,如果不懂KMP的话,最好先学学KMP再来学这个,会理解的更深刻一些。
 
代码如下:
=======================================================================================================================
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;

const int MAXN = 1e6+7;
const int MAXM = 26;
const int oo = 1e9+37;

char MumStr[MAXN];///母串

struct Ac_Trie_Node
{///Fail 失败节点
    Ac_Trie_Node *Fail, *next[MAXM];
    int leaf;///已这个节点为叶子节点的数目
};

void Insert(Ac_Trie_Node *root, char s[])
{///插入所有的模式串
    Ac_Trie_Node *p = root;

    for(int i=0; s[i]; i++)
    {
        int k = s[i]-'a';

        if(p->next[k] == NULL)
            p->next[k] = new Ac_Trie_Node();
        p = p->next[k];
    }

    p->leaf += 1;
}
void GetFail(Ac_Trie_Node *root)
{///构造失败指针
    queue<Ac_Trie_Node *> Q;
    Ac_Trie_Node *p = root, *temp;

    for(int i=0; i<MAXM; i++)
    {
        if(p->next[i] != NULL)
        {
            p->next[i]->Fail = root;
            Q.push(p->next[i]);
        }
    }

    while(Q.size())
    {
        p = Q.front();Q.pop();

        for(int i=0; i<MAXM; i++) if(p->next[i])
        {///如果节点p的next[i]不为空

            temp = p->Fail;///查找另一个最近的next[i]不为空的地方

            while(temp != NULL)
            {
                if(temp->next[i] != NULL)
                {///查找到
                    p->next[i]->Fail = temp->next[i];
                    break;
                }

                temp = temp->Fail;
            }

            if(temp == NULL)
                p->next[i]->Fail = root;

            Q.push(p->next[i]);
        }
    }
}
void FreeTrie(Ac_Trie_Node *root)
{///释放内存
    Ac_Trie_Node *p = root;

    for(int i=0; i<MAXM; i++)
    {
        if(p->next[i] != NULL)
            FreeTrie(p->next[i]);
    }

    free(p);
}
int Query(Ac_Trie_Node *root)
{
    Ac_Trie_Node *p = root, *temp;
    int sum=0;

    for(int i=0; MumStr[i]; i++)
    {
        int k = MumStr[i]-'a';

        while(!p->next[k] && p != root)
            p = p->Fail;

        if(!p->next[k])continue;///根节点下面没有这个字母

        temp = p = p->next[k];

        while(temp != root && temp->leaf != -1)
        {///查找路径上的所有子节串,因为每个子串只出现一次,所以赋值为-1,防止重搜
            sum += temp->leaf;
            temp->leaf = -1;
            temp = temp->Fail;
        }
    }

    return sum;
}

int main()
{
    int T;

    scanf("%d", &T);

    while(T--)
    {
        int M; char s[107];
        Ac_Trie_Node *root = new Ac_Trie_Node();

        scanf("%d", &M);

        while(M--)
        {
            scanf("%s", s);
            Insert(root, s);
        }

        GetFail(root);

        scanf("%s", MumStr);
        int ans = Query(root);

        printf("%d
", ans);

        FreeTrie(root);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/liuxin13/p/4750551.html