• 算法提高-AC自动机


    AC自动机其实就是Trie+KMP,AC自动机还可与稍微扩展一下,扩展成Trie图的形式(每次fial的时候可以一步到位,不需要一步一步慢慢跳)
    很好的一篇博客trie树和优化成trie图都说的很清楚

    AcWing 1282. 搜索关键词

    #include 
    #include 
    using namespace std;
    
    const int N = 1e4 + 10, S = 55, M = 1e6 + 10;
    int n, T;
    int cnt[N * S], q[N * S], tr[N * S][26], ne[N * S], idx;
    char str[M];
    
    void insert()
    {
        int p = 0;
        for (int i =  0; str[i]; ++ i)
        {
            int t = str[i] - 'a';
            if (!tr[p][t]) tr[p][t] = ++ idx;
            p = tr[p][t];
        }
        cnt[p] ++;
    }
    
    void build()//建立trie树
    {
        int hh = 0, tt = -1;
        for (int i = 0; i < 26; ++ i)
        {
            if (tr[0][i]) q[++tt] = tr[0][i];//之前没加if TLE了
        }
        
        while (hh <= tt)
        {
            int t = q[hh++];
            for (int i = 0; i < 26; ++ i)
            {
                int p = tr[t][i];
                if (p)
                {
                    int j = ne[t];
                    while (j && !tr[j][i]) j = ne[j];
                    if (tr[j][i]) j = tr[j][i];
                    ne[p] = j;
                    q[++tt] = p;
                }
            }
        }
    }
    
    void match()//匹配
    {
        int res = 0;
        cin >> str;
        for (int i = 0, j = 0; str[i]; ++ i)
        {
            int t = str[i] - 'a';
            while (j && !tr[j][t]) j = ne[j];
            
            if (tr[j][t]) j = tr[j][t];
            int p = j;
            while (p)
            {
                res += cnt[p];
                cnt[p] = 0;
                p = ne[p];
            }
        }
        
        cout << res << endl;
    }
    void solve()
    {
        memset(cnt, 0, sizeof cnt); 
        memset(tr, 0, sizeof tr);
        memset(ne, 0, sizeof ne);
        idx = 0;
        cin >> n;
        for (int i = 0; i < n; ++ i)
        {
            cin >> str;
            insert();
        }
        
        build();
        match();
    }
    int main()
    {
        cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    优化成trie图

    #include 
    #include 
    using namespace std;
    
    const int N = 1e4 + 10, S = 55, M = 1e6 + 10;
    int n, T;
    int cnt[N * S], q[N * S], tr[N * S][26], ne[N * S], idx;
    char str[M];
    
    void insert()
    {
        int p = 0;
        for (int i =  0; str[i]; ++ i)
        {
            int t = str[i] - 'a';
            if (!tr[p][t]) tr[p][t] = ++ idx;
            p = tr[p][t];
        }
        cnt[p] ++;
    }
    
    void build()//建立trie树
    {
        int hh = 0, tt = -1;
        for (int i = 0; i < 26; ++ i)
        {
            if (tr[0][i]) q[++tt] = tr[0][i];//之前没加if TLE了
        }
        
        while (hh <= tt)
        {
            int t = q[hh++];
            for (int i = 0; i < 26; ++ i)
            {
                int p = tr[t][i];
                //优化 相当于并查集路径压缩的思想
                if(!p) tr[t][i] = tr[ne[t]][i];//如果不存在t的子节点i
                else
                {
                    ne[p] = tr[ne[t]][i];
                    q[++tt] = p;
                }
            }
        }
    }
    
    void match()//匹配
    {
        int res = 0;
        cin >> str;
        for (int i = 0, j = 0; str[i]; ++ i)
        {
            int t = str[i] - 'a';
            j = tr[j][t];//不用一步一步跳判断是否存在tr[j][t]了,最差的情况是直接指向根节点
            int p = j;
            while (p)
            {
                res += cnt[p];
                cnt[p] = 0;
                p = ne[p];
            }
        }
        
        cout << res << endl;
    }
    void solve()
    {
        memset(cnt, 0, sizeof cnt); 
        memset(tr, 0, sizeof tr);
        memset(ne, 0, sizeof ne);
        idx = 0;
        cin >> n;
        for (int i = 0; i < n; ++ i)
        {
            cin >> str;
            insert();
        }
        
        build();
        match();
    }
    int main()
    {
        cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    优化到真正的线性复杂度
    在这里插入图片描述

  • 相关阅读:
    WebRTC视频采集模块
    JavaScript学习Day002
    本地电脑搭建SFTP服务器,并实现公网访问
    嵌入式Linux裸机开发(七)UART串口、IIC、SPI通信
    音视频开发之旅(67) - 变速不变调之sonic源码分析
    loj 10078 / 一本通 1500 / 洛谷 P5764【最短路】【dfs枚举排列】
    【路径规划-VRP问题】基于遗传算法求解出租车网约车接送客车辆路径规划问题附matlab代码
    Python3中.whl文件介绍
    Oracle-表空间管理
    CV复习:pooling的作用、反向传播及代码
  • 原文地址:https://blog.csdn.net/chirou_/article/details/132561522