AC自动机 ( 动态建树模板 )——Keywords Search ( HDU 2222 )

来源:互联网 发布:ipad软件下载排行榜 编辑:程序博客网 时间:2024/05/21 12:09
  • 题目链接:
    http://acm.hdu.edu.cn/showproblem.php?pid=2222

  • 分析:
    给出n个单词建树,然后给出一个字符串,搜索字符串里出现了多少个单词。直接套用AC自动机模板就可以。

  • AC自动机模板(含解析):

const int k = 26;const int MAXN = 500100;struct Node{    Node* ch[k], *fail;    int match;    void clear()    {        memset(this, 0, sizeof(Node));    }};Node * que[MAXN];struct ACAutomaton{    Node nodes[MAXN],  *root,  *superRoot, *cur; //全局变量    Node * newNode()  //从内存池中初始化一个结点    {        cur -> clear();        return cur++;    }    void clear()  //清空整个字典树    {        cur = nodes;        superRoot = newNode();        root = newNode();        root -> fail = superRoot;        for(int i=0;i<k;i++)      //superRoot为虚拟的超级根结点,所有孩子均指向实际的根结点,减少建立自动机的代码量            superRoot -> ch[i] = root;        superRoot->match = -1;    }    void insert(char *s)//插入每一个字符,match++    {        Node * t = root;        for(;*s;s++)        {            int x = *s - 'a';            if(t -> ch[x] == NULL)                t -> ch[x] = newNode();            t = t -> ch[x];        }        t -> match++;    }    void build()            //使用自动机前,要先生成失配指针    {        int p=0, q =0;        que[q++] = root;        while(p!=q)         //BFS求失配指针【非常关键的一步,可以好好理解】        {            Node*t = que[p++];            for(int i=0;i<k;i++)            {                if(t->ch[i])                {                    t -> ch[i] -> fail = t->fail ->ch[i];                    que[q++] = t->ch[i];                }else                    t->ch[i] = t -> fail ->ch[i];            }        }    }    int run(char *s)            //计算s中模式串出现的次数    {        int ans = 0;        Node * t = root;        for(; *s ; s++)        {            int x = *s - 'a';            t = t->ch[x];       //记住 t 每次迭代的值!!!便于理解            for(Node*u = t; u->match != -1;u = u->fail)            {                ans += u ->match;                u -> match = -1;   //避免重复计算            }        }        return ans;    }};
  • AC代码:
#include <cstdio>#include <iostream>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <cctype>#include <map>#include <set>#include <queue>using namespace std;typedef pair<int,int> Pii;typedef long long LL;typedef unsigned long long ULL;typedef double DBL;typedef long double LDBL;#define MST(a,b) memset(a,b,sizeof(a))#define CLR(a) MST(a,0)#define Sqr(a) ((a)*(a))const int k = 26;const int MAXN = 500100;struct Node{    Node* ch[k], *fail;    int match;    void clear()    {        memset(this, 0, sizeof(Node));    }};Node * que[MAXN];struct ACAutomaton{    Node nodes[MAXN],  *root,  *superRoot, *cur; //全局变量    Node * newNode()  //从内存池中初始化一个结点    {        cur -> clear();        return cur++;    }    void clear()  //清空整个字典树    {        cur = nodes;        superRoot = newNode();        root = newNode();        root -> fail = superRoot;        for(int i=0;i<k;i++)      //superRoot为虚拟的超级根结点,所有孩子均指向实际的根结点,减少建立自动机的代码量            superRoot -> ch[i] = root;        superRoot->match = -1;    }    void insert(char *s)    {        Node * t = root;        for(;*s;s++)        {            int x = *s - 'a';            if(t -> ch[x] == NULL)                t -> ch[x] = newNode();            t = t -> ch[x];        }        t -> match++;    }    void build()            //使用自动机前,要先生成失配指针    {        int p=0, q =0;        que[q++] = root;        while(p!=q)         //BFS求失配指针        {            Node*t = que[p++];            for(int i=0;i<k;i++)            {                if(t->ch[i])                {                    t -> ch[i] -> fail = t->fail ->ch[i];                    que[q++] = t->ch[i];                }else                    t->ch[i] = t -> fail ->ch[i];            }        }    }    int run(char *s)            //在自动机上与匹配串s进行匹配    {        int ans = 0;        Node * t = root;        for(; *s ; s++)        {            int x = *s - 'a';            t = t->ch[x];            for(Node*u = t; u->match != -1;u = u->fail)            {                ans += u ->match;                u -> match = -1;            }        }        return ans;    }};int n;ACAutomaton j;char s[1000100];int main(){    int T;    scanf("%d", &T);    while(T--)    {        scanf("%d", &n);        j.clear();        while(n--)        {            scanf("%s", s);            j.insert(s);        }        j.build();        scanf("%s", s);        printf("%d\n", j.run(s));    }    return 0;}
0 0
原创粉丝点击