zoukankan      html  css  js  c++  java
  • LA 4670 Dominating Patterns (AC自动机)

    题意:给定n个字符串和一个文本串,查找哪个字符串出现的次数的最多。

    析:一匹配多,很明显是AC自动机。只需要对原来的进行修改一下,就可以得到这个题的答案,

    计算过程中,要更新次数,并且要映射字符串。如果用KMP肯定会超时。

    代码如下:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <string>
    #include <queue>
    
    using namespace std;
    const int maxn = 1000000 + 5;
    const int sigma = 26;
    const int maxnode = 70 * 150 + 5;
    map<string, int> ms;
    //AC自动机
    struct AhoCorasickAutomata{
        int cnt[155];
        int ch[maxnode][sigma];
        int f[maxnode];//失配函数
        int val[maxnode];//每个字符串结尾都有一个非0的val
        int last[maxnode];//链表的下一个结点
        int sz;
    
        void init(){
            sz = 1;
            memset(ch[0], 0, sizeof(ch[0]));
            memset(cnt, 0, sizeof(cnt));
            ms.clear();
        }
    
        int idx(char c){  return c - 'a'; }//进行编号
        //插入字符串
        void insert(char *s, int v){
            int u = 0, n = strlen(s);
            for(int i = 0; i < n; ++i){
                int c = idx(s[i]);
                if(!ch[u][c]){
                    memset(ch[sz], 0, sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;
            ms[s] = v;
        }
        //查找字符串
        void find(char *T){
            int n = strlen(T);
            int j = 0;// 当前结点编号,初始为根结点
            for(int i = 0; i < n; ++i){
                int c = idx(T[i]);
                while(j && !ch[j][c])  j = f[j];
                j = ch[j][c];
                if(val[j])  print(j);
                else if(last[j])  print(last[j]);//找到
            }
        }
        //打印结果,也就是更新次数
        void print(int j){
            if(j){
                ++cnt[val[j]];
                print(last[j]);
            }
        }
        //获得失配函数
        int getFail(){
            queue<int> q;
            f[0] = 0;
            //初始化队列
            for(int c = 0; c < sigma; ++c){
                int u = ch[0][c];
                if(u){ f[u] = 0; q.push(u);  last[u] = 0; }
            }
            //bfs
            while(!q.empty()){
                int r = q.front();  q.pop();
                for(int c = 0; c < sigma; ++c){
                    int u = ch[r][c];
                    if(!u) continue;
    
                    q.push(u);
                    int v = f[r];
                    while(v && !ch[v][c])  v = f[v];
                    f[u] = ch[v][c];
                    last[u] = val[f[u]] ? f[u] : last[f[u]];
                }
            }
        }
    
    };
    
    AhoCorasickAutomata ac;
    char text[maxn], p[155][75];
    
    int main(){
        int n;
        while(scanf("%d", &n) == 1 && n){
            ac.init();
            for(int i = 1; i <= n; ++i){
                scanf("%s", p[i]);
                ac.insert(p[i], i);
            }
    
            ac.getFail();
            scanf("%s", text);
            ac.find(text);
            int m = -1;
            for(int i = 1; i <= n; ++i)
                m = max(m, ac.cnt[i]);
            printf("%d
    ", m);
    
            for(int i = 1; i <= n; ++i)
                if(ac.cnt[ms[p[i]]] == m)  printf("%s
    ", p[i]);
    
        }
        return 0;
    }
    
  • 相关阅读:
    python 包管理工具 pip 的配置
    Python 变量作用域 LEGB (下)—— Enclosing function locals
    Python 变量作用域 LEGB (上)—— Local,Global,Builtin
    2020 Java 面试题 小结 (答案慢慢补上,有错误请指出)
    mysql 根据日期(date)做年,月,日分组统计查询
    jvm指令
    正则表达式 分割地址 获取省市区详细地址
    .Net 异常记录
    WCF设计服务协议(一)
    plsql ORA-01789:查询块具有不正确的结果列数
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/5558633.html
Copyright © 2011-2022 走看看