ac自动机静态比动态快

ac自动机提高效率的一个办法是实现后缀链接,即增加一个指针指向下一个单词节点,而不是盲目的沿着失败指针查询。
however,lightoj1427迷之超时,难道动态建树比静态建树快很多吗?再写个静态的试试吧……

TAT:我又写了个静态的,跑了2300多ms,另外struct里面能开的空间并不能很大,本机开辟int ch[505*505][26]时会编译不过。同时写会了静态和动态,对ac自动机的掌握加深了不少。后面附上AC代码

题意:求解各个模式串在文本串中出现的次数

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 1000005;
const int maxm = 505;
char s[maxn],p[maxm][maxm];

struct Node
{
    Node *next[26];
    Node *fail;
    Node *last; //后缀链接,全靠你来优化查询了
    bool isWord;
    int cnt;
    Node() { memset(next,0,sizeof(next)); isWord = false; fail = NULL; last = NULL; cnt = 0; }
};
Node *Q[maxn];

struct ACMachine
{
    Node *root;
    ACMachine() { root = new Node(); }
    ~ACMachine()
    {
        destroy(root);
    }
    void destroy(Node *rt)
    {
        if(!rt) return;
        for(int i = 0; i < 26; i++)
            destroy(rt->next[i]);
        delete rt;
    }
    void Insert(char str[])
    {
        Node *p = root;
        for(int i = 0; str[i] != 0; i++)
        {
            int index = str[i] - 'a';
            if(p->next[index] == NULL) p->next[index] = new Node();
            p = p->next[index];
        }
        p->isWord = true;
    }
    void build_ACMachine()
    {
        int head = 0,tail = 0;
        Q[tail++] = root;
        while(head < tail)
        {
            Node *fa = Q[head++];
            for(int i = 0; i < 26; i++)
            {
                Node *son = fa->next[i];
                if(son != NULL)
                {
                    Node *temp = fa->fail;
                    while(temp != NULL && temp->next[i] == NULL) temp = temp->fail;
                    if(temp == NULL) son->fail = root;
                    else
                    {
                        son->fail = temp->next[i];
                        if(temp->next[i]->isWord) son->last = temp->next[i];
                        else son->last = temp->next[i]->last;
                    }
                    Q[tail++] = son;
                }
            }
        }
    }
    void query(char str[])
    {
        Node *p = root;
        for(int i = 0; str[i] != 0; i++)
        {
            int index = str[i] - 'a';
            while(p != NULL && p->next[index] == NULL)
                p = p->fail;
            if(p == NULL) p = root;
            else
            {
                p = p->next[index];
                if(p->isWord) p->cnt++;
                Node *temp = p->last;
                while(temp != NULL)
                {
                    temp->cnt++;
                    temp = temp->last;
                }
            }
        }
    }
    int getAns(char str[])
    {
        Node *p = root;
        for(int i = 0; str[i]; i++)
        {
            int index = str[i] - 'a';
            p = p->next[index];
        }
        return p->cnt;
    }
};

int main()
{
    int T,cas = 1;
    scanf("%d" ,&T);
    while(T--)
    {
        int n;
        scanf("%d" ,&n);
        scanf("%s" ,s);
        ACMachine ac;
        for(int i = 0; i < n; i++)
        {
            scanf("%s" ,p[i]);
            ac.Insert(p[i]);
        }
        ac.build_ACMachine();
        ac.query(s);
        printf("Case %d:\n",cas++);
        for(int i = 0; i < n; i++)
        {
            printf("%d\n",ac.getAns(p[i]));
        }
    }
    return 0;
}

AC代码:静态建ac自动机

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 1000005;
const int maxm = 505;
const int maxnode = 505*505;

char s[maxn],p[maxm][maxm];
int ch[maxnode][26];
int fail[maxnode];
bool isWord[maxnode];
int last[maxnode];
int cnt[maxnode];
int sz;
void init()
{
    sz = 1;
    memset(ch,0,sizeof(ch));
    memset(isWord,0,sizeof(isWord));
    memset(last,0,sizeof(last));
    memset(fail,0,sizeof(fail));
    memset(cnt,0,sizeof(cnt));
    memset(p,0,sizeof(p));
    memset(s,0,sizeof(s));
}
void Insert(char *str)
{
    int u = 0;
    for(int i = 0; str[i]; i++)
    {
        int index = str[i] - 'a';
        if(ch[u][index] == 0) ch[u][index] = sz++;
        u = ch[u][index];
    }
    isWord[u] = true;
}
void build_ACMachine()
{
    int u = 0;
    fail[u] = -1;
    queue<int> q;
    q.push(u);
    while(!q.empty())
    {
        int fa = q.front();
        q.pop();
        for(int i = 0; i < 26; i++)
        {
            int son = ch[fa][i];
            if(son != 0)
            {
                int temp = fail[fa];
                while(temp != -1 && ch[temp][i] == 0) temp = fail[temp];
                if(temp == -1) fail[son] = 0;
                else
                {
                    fail[son] = ch[temp][i];
                    if(isWord[fail[son]] == true) last[son] = fail[son];
                    else last[son] = last[fail[son]];
                }
                q.push(son);
            }
        }
    }
}
void query(char *str)
{
    int u = 0;
    for(int i = 0; str[i]; i++)
    {
        int index = str[i] - 'a';
        while(u != -1 && ch[u][index] == 0)
            u = fail[u];
        if(u == -1) u = 0;
        else
        {
            u = ch[u][index];
            int temp = u;
            while(temp != 0)
            {
                if(isWord[temp])
                    cnt[temp]++;
                temp = last[temp];
            }
        }
    }
}
int getAns(char *str)
{
    int u = 0;
    for(int i = 0; str[i]; i++)
    {
        int index = str[i] - 'a';
        u = ch[u][index];
    }
    return cnt[u];
}

int main()
{
    int T,cas = 1;
    scanf("%d",&T);
    while(T--)
    {
        init();
        int n;
        scanf("%d",&n);
        scanf("%s",s);
        for(int i = 0; i < n; i++)
        {
            scanf("%s",p[i]);
            Insert(p[i]);
        }
        build_ACMachine();
        query(s);
        printf("Case %d:\n",cas++);
        for(int i = 0; i < n; i++)
        {
            printf("%d\n",getAns(p[i]));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值