P3808 AC 自动机(简单版)

这两题始终做完 P5357 【模板】AC 自动机 这题的基础上做的

P3808 AC 自动机(简单版)

更改一下范围和打印内容。

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
#define endl "\n"
using namespace std;
const int MAX0 = 2e6 + 3;
const int MAXN = 2e6 + 3;
struct {
    int trie[MAX0][26], cnt = 0;//字典树(a~z)
    int output[MAX0];             // 输出标记,及以此位置结尾的的模式串有多少个;(很少用)
    int fail[MAX0];//失配指针
    int ins[MAXN], insi;//输入第i个模式串的结尾位置vector<int> ins;
    int time[MAX0];             // 在匹配串中,这个位置出现过多少次;

    // 初始化
    void init() {
        memset(trie, 0, sizeof(trie));
        memset(fail, 0, sizeof(fail));
        memset(ins, 0, sizeof(ins));
        memset(output, 0, sizeof(output));
        memset(time, 0, sizeof(time));
        cnt = 0, insi = 0;
    }
    void inittime() {
        memset(time, 0, sizeof(time));
    }


    //插入模式串,建立tire树(字典树)
    void insert(string s) {
        int sn = s.size();
        int i = 0;
        for (int z = 0; z < sn; z++) {
            int j = s[z] - 'a';
            if (!trie[i][j]) {
                trie[i][j] = ++cnt;
            }
            i = trie[i][j];
        }
        ins[insi++] = i;
        output[i]++;
    }

    // 构建失配指针+建立直通表(优化trie)(避免绕圈)
    void build() {
        queue<int> q;
        for (int j = 0; j < 26; j++) {
            if (trie[0][j] != 0) {
                fail[trie[0][j]] = 0;
                q.push(trie[0][j]);
            }
        }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int j = 0; j < 26; j++) {
                if (trie[u][j] != 0) {
                    fail[trie[u][j]] = trie[fail[u]][j];
                    q.push(trie[u][j]);
                    
                }
                else {
                    trie[u][j] = trie[fail[u]][j];
                }
            }
        }
    }
    //建立fail的反树,避免遍历文章时绕圈
    void opposedfail() {
        vector<vector<int>> opposed(cnt+1, vector<int>());
        vector<bool> visited(cnt + 1, false);
        for (int i = 1; i <= cnt; i++) {
            opposed[fail[i]].push_back(i);
        }
        stack<int> q;
        q.push(0);
        while (!q.empty()) {
            int i = q.top();
            if (!visited[i]) {
                visited[i] = true;
                for (int j = 0; j < opposed[i].size(); j++) {
                    q.push(opposed[i][j]);
                }
            }
            else {
                time[fail[i]] += time[i];
                q.pop();
            }
        }
    }
    

    //匹配串匹配
    void search(string s) {
        int sn = s.size();
        int i = 0;
        for (int z = 0; z < sn; z++) {
            int j = s[z] - 'a';
            time[trie[i][j]]++;
            i = trie[i][j];
        }
        opposedfail();
    }

}AC;
void solve() {
    int n;
    AC.init();
    cin >> n;
    string s;
    for (int i = 0; i < n; i++) {
        cin >> s;
        AC.insert(s);
    }

    AC.build();

    cin >> s;
    AC.search(s);
    int ans = 0;
    for (int i = 0; i < AC.insi; i++) {
        if (AC.time[AC.ins[i]]) {
            ans++;
        }
    }
    cout << ans << endl;
    return;
}
int main(){
	ios::sync_with_stdio(false);        // 禁用同步
    std::cin.tie(nullptr),std::cout.tie(nullptr);             // 解除cin与cout绑定
    int t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

P3796 AC 自动机(简单版 II)

同上修改

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
#define endl "\n"
using namespace std;
const int MAX0 = 2e4 + 3;
const int MAXN = 150 + 3;
struct {
    int trie[MAX0][26], cnt = 0;//字典树(a~z)
    int output[MAX0];             // 输出标记,及以此位置结尾的的模式串有多少个;(很少用)
    int fail[MAX0];//失配指针
    int ins[MAXN], insi;//输入第i个模式串的结尾位置vector<int> ins;
    int time[MAX0];             // 在匹配串中,这个位置出现过多少次;

    // 初始化
    void init() {
        memset(trie, 0, sizeof(trie));
        memset(fail, 0, sizeof(fail));
        memset(ins, 0, sizeof(ins));
        memset(output, 0, sizeof(output));
        memset(time, 0, sizeof(time));
        cnt = 0, insi = 0;
    }
    void inittime() {
        memset(time, 0, sizeof(time));
    }


    //插入模式串,建立tire树(字典树)
    void insert(string s) {
        int sn = s.size();
        int i = 0;
        for (int z = 0; z < sn; z++) {
            int j = s[z] - 'a';
            if (!trie[i][j]) {
                trie[i][j] = ++cnt;
            }
            i = trie[i][j];
        }
        ins[insi++] = i;
        output[i]++;
    }

    // 构建失配指针+建立直通表(优化trie)(避免绕圈)
    void build() {
        queue<int> q;
        for (int j = 0; j < 26; j++) {
            if (trie[0][j] != 0) {
                fail[trie[0][j]] = 0;
                q.push(trie[0][j]);
            }
        }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int j = 0; j < 26; j++) {
                if (trie[u][j] != 0) {
                    fail[trie[u][j]] = trie[fail[u]][j];
                    q.push(trie[u][j]);
                    
                }
                else {
                    trie[u][j] = trie[fail[u]][j];
                }
            }
        }
    }
    //建立fail的反树,避免遍历文章时绕圈
    void opposedfail() {
        vector<vector<int>> opposed(cnt+1, vector<int>());
        vector<bool> visited(cnt + 1, false);
        for (int i = 1; i <= cnt; i++) {
            opposed[fail[i]].push_back(i);
        }
        stack<int> q;
        q.push(0);
        while (!q.empty()) {
            int i = q.top();
            if (!visited[i]) {
                visited[i] = true;
                for (int j = 0; j < opposed[i].size(); j++) {
                    q.push(opposed[i][j]);
                }
            }
            else {
                time[fail[i]] += time[i];
                q.pop();
            }
        }
    }
    

    //匹配串匹配
    void search(string s) {
        int sn = s.size();
        int i = 0;
        for (int z = 0; z < sn; z++) {
            int j = s[z] - 'a';
            time[trie[i][j]]++;
            i = trie[i][j];
        }
        opposedfail();
    }

}AC;
int n;
void solve() {
    AC.init();
    vector<string >f(n);
    for (int i = 0; i < n; i++) {
        cin >> f[i];
        AC.insert(f[i]);
    }

    AC.build();
    string s;
    cin >> s;
    AC.search(s);
    int max_f = 0;
    for (int i = 0; i < AC.insi; i++) {
        max_f = max(AC.time[AC.ins[i]], max_f);
    }
    cout << max_f << endl;
    for (int i = 0; i < AC.insi; i++) {
        if (AC.time[AC.ins[i]] == max_f) {
            cout << f[i] << endl;
        }
    }
    return;
}
int main(){
	ios::sync_with_stdio(false);        // 禁用同步
    std::cin.tie(nullptr),std::cout.tie(nullptr);             // 解除cin与cout绑定
    int t = 1;
    //cin >> t;
    while (cin>>n) {
        if (n == 0) {
            break;
        }
        solve();
    }
    return 0;
}
相关推荐
HXhlx2 小时前
CART决策树基本原理
算法·机器学习
Wect3 小时前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript
颜酱3 小时前
单调队列:滑动窗口极值问题的最优解(通用模板版)
javascript·后端·算法
Gorway10 小时前
解析残差网络 (ResNet)
算法
拖拉斯旋风10 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect10 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript
灵感__idea1 天前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
Wect1 天前
LeetCode 130. 被围绕的区域:两种解法详解(BFS/DFS)
前端·算法·typescript
NAGNIP2 天前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
颜酱2 天前
单调栈:从模板到实战
javascript·后端·算法