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\n", m);

        for(int i = 1; i <= n; ++i)
            if(ac.cnt[ms[p[i]]] == m)  printf("%s\n", p[i]);

    }
    return 0;
}
时间: 2024-10-25 15:59:55

LA 4670 Dominating Patterns (AC自动机)的相关文章

LA 4670 Dominating Patterns (AC自动机)

题意:给定一个一篇文章,然后下面有一些单词,问这些单词在这文章中出现过几次. 析:这是一个AC自动机的裸板,最后在匹配完之后再统计数目就好. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <ios

UVALive 4670 Dominating Patterns --AC自动机第一题

题意:多个模板串,一个文本串,求出那些模板串在文本串中出现次数最多. 解法:AC自动机入门模板题. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <string> #include <vector> #in

UVALive - 4670 Dominating Patterns AC 自动机

input n 1<=n<=150 word1 word2 ... wordn 1<=len(wirdi)<=70 s 1<=len(s)<=1000000 output 最多出现次数 出现最多的串,按输入顺序输出,可能出现相同串,也要输出 做法:用一个end数组记下每个串结尾的字符的下标,对应val为1,每次找到就将val++,然后找到最大的val,输出最大val对应的字符串 1 #include <cstdio> 2 #include <queue

uva 1449 - Dominating Patterns(AC自动机)

题目练级:uva 1449 - Dominating Patterns 题目大意:有一个由小写字母组成的字符串集和一个文本T,要求找出那些字符串在文本中出现的次数最多. 解题思路:将字符串集建立AC自动机,然后传入T进行匹配,对每个匹配上的字符串多应次数加1,最后找出最大值.出现次数与最大值相同的字符串输出.注意字符集中出现相同字符的情况. #include <cstdio> #include <cstring> #include <queue> #include &l

LA4670 Dominating Patterns AC自动机模板

Dominating Patterns 每次看着别人的代码改成自己的模板都很头大...空间少了个0卡了好久 裸题,用比map + string更高效的vector代替蓝书中的处理方法 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7

AC自动机 LA 4670 Dominating Patterns

题目传送门 题意:训练之南(P216) 分析:求出现最多次数的字串,那么对每个字串映射id,cnt记录次数求最大就可以了. #include <bits/stdc++.h> using namespace std; const int N = 150 + 5; const int NODE = N * 70; const int LEN = 1e6 + 5; const int SIZE = 26; struct AC { int ch[NODE][SIZE], fail[NODE], val

uvalive 4670 Dominating Patterns

在文本串中找出现次数最多的子串. 思路:AC自动机模板+修改一下print函数. 1 #include<stdio.h> 2 #include<math.h> 3 #include<stdio.h> 4 #include<stdlib.h> 5 #include<iostream> 6 #include<string> 7 #include<memory.h> 8 #include<map> 9 #includ

Dominating Patterns (AC 自动鸡模版题, 出现次数最多的子串)

传送门 题意: 给你n个模式串, 再给你一个 文本串,问模式串在文本串中出现次数最多是多少. 出现次数最多的模式串有哪些. 解: 模版题. #include <bits/stdc++.h> #define LL long long #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define mem(i, j) memset(i, j

AC自动机

AC自动机 直接学AC自动机比较难理解,强烈建议先学完KMP和字典树并进行一定的练习后,对于失配指针和字典树构造有一定理解后再来学AC自动机的内容.有关AC自动机的详细介绍可见刘汝佳的<算法竞赛入门经典训练指南>P214. 给你一个字典(包含n个不重复的单词),然后给你一串连续的字符串文本(长为len),问你该文本里面的哪些位置正好出现了字典中的某一个或某几个单词?输出这些位置以及出现的单词. 这个问题可以用n个单词的n次KMP算法来做(效率为O(n*len*单词平均长度)),也可以用1个字典