ac自动机

ac自动机主要是字典树和KMP算法的结合,主要解决多模匹配问题。
KMP算法里面有一个叫做next数组的,现在我们把所有的模式串都建立成一个字典树,每次查询的时候就在这个字典树里面找。
思路讲解
代码讲解,有错误
训练题目以hdu2222
首先我们先建立一棵字典树,开辟一个数组trix[20][26],一层其实只有一个字符,只有这个字符的值不为0;
接下来主要构思以下fail数组的构造方法。
首先,我们要用bfs的方式来一层一层的建立fail数组。对于一个节点,我们先看它的父节点的fail数组有没有指向当前节点的字符的,如果有,就fail[当前节点] = trix[fail[父亲]][当前节点的字符]
对于查询,主要就是如果当前目标串的字符能找到,就直接加入所有的cnt,这个cnt包括了以当前字典树已匹配的后缀,注意,哪怕当前now位置的字符不是字符的结尾,也要加cnt,比如sher和he,sher还没有找完,但是找到she的时候就应该把he的cnt也加进去了,然后就是cnt没加一次记得清零,避免一个模式串重复加入。比如:
在这里插入图片描述
如果不清零的话,he就会在ashe和bshe都加一个,答案就会变成4,就不对了。
上面的解释都不好因为这个东西得有图片视频才好看,所以直接打开上面得链接才是对的。
贴一下hdu的板子,全是自己手打的,理解最重要:

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;

const int maxn = 1e6 + 50;
const int maxn_total = 5e5 + 50;
int trix[maxn_total][26];
int fail[maxn_total];
int cnt[maxn_total];
char ch[maxn];
queue<int>que;
struct Trix{
    int sz;
    Trix() {sz = 1; for (int i = 0; i < 26; i++) trix[0][i] = 0;}
    void insert(char *s) {
        int n = strlen(s);
        int now = 0;
        for (int i = 0; i < n; i++) {
            int ch = s[i] - 'a';
            if (!trix[now][ch]) {
                for (int j = 0; j < 26; j++) trix[sz][j] = 0;
                trix[now][ch] = sz++;
                cnt[sz] = 0;
            }
            now = trix[now][ch];
        }
        cnt[now]++;
    }
};

void build() {
    fail[0] = 0;
    while(!que.empty()) que.pop();
    for (int i = 0; i < 26; i++)
        if (trix[0][i]) {
            que.push(trix[0][i]);
            fail[trix[0][i]] = 0;
        }

    while(!que.empty()) {
        int u = que.front(); que.pop();
        for (int i = 0; i < 26; i++) {
            if (trix[u][i]) {
                int v = fail[u];
                while(v && !trix[v][i]) v = trix[v][i];
                fail[trix[u][i]] = trix[v][i];
                que.push(trix[u][i]);
            } else trix[u][i] = trix[fail[u]][i];
        }
    }
}

int Get(int now) {
    int ans = 0;
    while(now) {
        ans += cnt[now];
        cnt[now] = 0;
        now = fail[now];
    }
    return ans;
}

int match(char *s) {
    int n = strlen(s), now = 0;
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int ch = s[i] - 'a';
        now = trix[now][ch];
        if (!now) continue;
        ans += Get(now);
    }
    return ans;
}



int main() {
    int T; scanf("%d",&T);
    while(T--) {
        Trix tree;
        int m; scanf("%d", &m);
        for (int i = 0; i < m; i++) {
            scanf("%s", &ch);
            tree.insert(ch);
        }
        build();
        scanf("%s",&ch);
        printf("%d\n",match(ch));
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值