ac自动机(A. 【例题1】单词查询+B. 【例题2】单词频率)

ac自动机含义:tire+KMp;

A. 【例题1】单词查询:

        本题主要是查询,可以建立一个cnt数组,和tire树中含义一样,最后定义一个ans,将ans加上查询到的cnt,输出ans就行了。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e4 + 10, M = 1e6 + 10;
int ch[M][30], n, idx = 0, cnt[M], ne[M], ans, heap[M];
char str[M];
inline void insert(char str[]) {
    int p = 1, n = strlen(str + 1);
    for (int i = 1; i <= n; i++) {
        int u = str[i] - 'a';
        if (!ch[p][u]) {
            ch[p][u] = ++idx;
            memset(ch[idx], 0, sizeof ch[idx]);
        }
        p = ch[p][u];
    }
    cnt[p]++;
    return;
}
inline void build() {
    for (int i = 0; i < 26; i++) {
        ch[0][i] = 1;
    }
    heap[1] = 1, ne[1] = 0;
    for (int q1 = 1, q2 = 1; q1 <= q2; q1++) {
        int u = heap[q1];
        for (int i = 0; i < 26; i++) {
            if (!ch[u][i])
                ch[u][i] = ch[ne[u]][i];//路径压缩,在寻找ne中减少迭代次数
            else {
                heap[++q2] = ch[u][i];//bfs();
                ne[ch[u][i]] = ch[ne[u]][i];//向后寻找ne
            }
        }
    }
    return;
}
inline void find(char str[]) {
    int p = 1, len = strlen(str + 1);
    for (int i = 1; i <= len; i++) {
        int u = str[i] - 'a';
        int k = ch[p][u];
        while (k > 1) {
            ans += cnt[k];//遍历每一个cnt,找到匹配的前缀
            cnt[k] = 0;
            k = ne[k];
        }
        p = ch[p][u];
    }
    return;
}
int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        ans = 0, idx = 1;
        memset(cnt, 0, sizeof cnt);
        memset(heap, 0, sizeof heap);
        for (int i = 0; i < 26; i++) ch[0][i] = 1, ch[1][i] = 0;//初始化
        for (int i = 1; i <= n; i++) {
            scanf("%s", str + 1);
            insert(str);//tire树中的插入
        }
        build();
        scanf("%s", str + 1);
        find(str + 1);
        cout << ans << endl;
    }
    return 0;
}

B. 【例题2】单词频率:
本题主要是查询出现次数,可以建立一个sum数组,最后通过ne对其求一遍前缀和就可以了,同时也要使用cnt来存储编号(ne要走到底),code:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int M = 1e6 + 10;
char str[M];
int ch[M][30], ne[M], que[M], sum[M], sum1[M], pos[M], idx = 1, ans = 0, n, tot;
inline void insert(char str[]) {
    int p = 1, len = strlen(str);
    for (int i = 0; i < len; i++) {
        int u = str[i] - 'a';
        if (!ch[p][u])
            ch[p][u] = ++idx;
        p = ch[p][u];
        sum[p]++;
    }
    pos[++tot] = p;
    return;
}
inline void bfs() {
    for (int i = 0; i < 26; i++) ch[0][i] = 1;
    que[1] = 1, ne[1] = 0;
    for (int q1 = 1, q2 = 1; q1 <= q2; q1++) {
        int u = que[q1];
        for (int i = 0; i < 26; i++) {
            if (!ch[u][i])
                ch[u][i] = ch[ne[u]][i];
            else {
                que[++q2] = ch[u][i];
                ne[ch[u][i]] = ch[ne[u]][i];
            }
        }
    }
    for (int i = idx; i >= 0; i--) {
        sum1[que[i]] = sum[que[i]];
    }
    for (int i = idx; i >= 0; i--) {
        sum1[ne[que[i]]] += sum1[que[i]];
    }
}
int main() {
    cin >> n;
    idx = 1;
    for (int i = 1; i <= n; i++) {
        scanf("%s", str);
        insert(str);
    }
    bfs();
    for (int i = 1; i <= n; i++) {
        cout << sum1[pos[i]] << endl;
    }
    return 0;
}

如有疑问可以来私信问我,本人会在第一时间内回复

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值