zoukankan      html  css  js  c++  java
  • hdu-2222(ac自动机模板)

    题意:给你一个长度为n的单词表,一个文本串,问你这个文本串中出现了单词表中多少个单词;

    解题思路:ac自动机的模板题,可以直接当模板用;

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn=1005000;
    struct node
    {
        node *next[27];
        node *fail;
        int sum;
    };
    char t[100];
    char s[1000500];
    int cnt;
    node *root;
    node *que[maxn];
    int head,tail;
    node* newnode()
    {
        node *p=new node;
        for(int i=0;i<26;i++)
            p->next[i]=NULL;
        p->sum=0;p->fail=0;
        return p;
    }
    void build_trie(char *s)
    {
        node *p=root;
        int slen=strlen(s);
        for(int i=0;i<slen;i++)
        {
            int id=s[i]-'a';
            if(p->next[id]==NULL)
            {
                p->next[id]=newnode();
            }
            p=p->next[id];
        }
        p->sum++;
    }
    void build_fail()
    {
        head=0;
        tail=1;
        que[head]=root;
        node *p;
        node *temp;
        while(head<tail)
        {
            temp=que[head++];
            for(int i=0;i<26;i++)
            {
                if(temp->next[i])
                {
                    if(temp==root)
                    {
                        temp->next[i]->fail=root;//root的儿子的fail全部指向root;
                    }
                    else
                    {
                        //找temp儿子的指针;
                        p=temp->fail;//temp的指向;
                        while(p)
                        {
                            if(p->next[i])//如果temp的指向存在且和儿子相同,儿子指向为这个;
                            {
                                temp->next[i]->fail=p->next[i];
                                break;
                            }
                            p=p->fail;
                        }
                        if(p==NULL)
                            temp->next[i]->fail=root;//儿子指向根节点;
                    }
                    que[tail++]=temp->next[i];
                }
            }
        }
    }
    void ac_automation(char *s)
    {
        node *p=root;
        int slen=strlen(s);
        for(int i=0;i<slen;i++)
        {
            int id=s[i]-'a';
            while(!p->next[id]&&p!=root)
                p=p->fail;
            p=p->next[id];
            if(!p)
                p=root;
            node *temp=p;
            while(temp!=root)
            {
    
                if((temp->sum)>=0)
                {
                    cnt+=temp->sum;
                    temp->sum=-1;
                }
                else
                    break;
                temp=temp->fail;
            }
        }
    }
    void Delete(node *&top)
    {
        if(top==NULL)
            return;
        for(int i=0;i<26;i++)
            Delete(top->next[i]);
        delete top;
    }
    int main()
    {
        int tt;
        int n;
        scanf("%d",&tt);
        while(tt--)
        {
            root=newnode();
            scanf("%d",&n);
            while(n--)
            {
                scanf("%s",t);
                build_trie(t);
            }
            scanf("%s",s);
            cnt=0;
            build_fail();
            ac_automation(s);
            Delete(root);
            printf("%d
    ",cnt);
        }
    }
    

      附上非指针版本:

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    using namespace std;
    const int maxn=1000500;
    const int N=500050;
    int trie[N][26],fail[N],tot;
    int sum[N];
    bool visit[N];
    char s[maxn];
    char t[60];
    void build_trie(char *str)
    {
        int root=0;
        int slen=strlen(str);
        for(int i=0;i<slen;i++)
        {
            int id=str[i]-'a';
            if(!trie[root][id])
            {
                trie[root][id]=++tot;
            }
            root=trie[root][id];
        }
        sum[root]++;
    }
    void build_fail()
    {
        queue<int>q;
        for(int i=0;i<26;i++)
        {
            if(trie[0][i]!=0)
                q.push(trie[0][i]);
        }
        while(!q.empty())
        {
            int now=q.front();q.pop();
            for(int i=0;i<26;i++)
            {
                if(!trie[now][i])
                {
                    trie[now][i]=trie[fail[now]][i];
                    continue;
                }
                fail[trie[now][i]]=trie[fail[now]][i];
                q.push(trie[now][i]);
            }
        }
    }
    int ac(char *str)
    {
        int root=0,ans=0;
        int slen=strlen(str);
        for(int i=0;i<slen;i++)
        {
            visit[root]=1;
            int id=str[i]-'a';
            int y=trie[root][id];
            while(y&&!visit[y])
            {
                visit[y]=1;
                if(sum[y])
                {
                    ans=ans+sum[y];
                    sum[y]=0;
                }
                y=fail[y];
            }
            root=trie[root][id];
        }
        return ans;
    }
    void init()
    {
        memset(trie,0,sizeof(trie));
        memset(sum,0,sizeof(sum));
        memset(visit,0,sizeof(visit));
        memset(fail,0,sizeof(fail));
        tot=0;
    }
    int main()
    {
        int n;
        int tt;
        scanf("%d",&tt);
        while(tt--)
        {
            init();
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%s",t);
                build_trie(t);
            }
            build_fail();
            scanf("%s",s);
            printf("%d
    ",ac(s));
        }
    }
    

      

  • 相关阅读:
    Codeforces 754A Lesha and array splitting (搜索)
    浅入分析Linux
    MakeFile基本使用
    Mac 安装YCM
    Homebrew 配置
    虚拟机复制操作CentOS6导致eth0转为eth0以至于网络服务启动失败的解决方案
    Kickstart安装
    Linux编译安装MySQL
    Python源码读后小结
    编译原理小结
  • 原文地址:https://www.cnblogs.com/huangdao/p/9600408.html
Copyright © 2011-2022 走看看