码迷,mamicode.com
首页 > 其他好文 > 详细

AC自动机

时间:2017-09-09 15:23:25      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:后缀   ons   div   const   show   pre   ret   模板   clu   

1、uva 1449/LA 4670 Dominating Patterns

  题意:有n个模板串和一个文本串,找出哪些模板串在文本串中出现次数最多。

  思路:AC自动机模板

技术分享
  1 #include<cstring>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<map>
  5 #include<string>
  6 using namespace std;
  7 
  8 const int SIGMA_SIZE = 26;
  9 const int MAXNODE = 11000;
 10 const int MAXS = 150 + 10;
 11 
 12 map<string, int> ms;
 13 
 14 struct ACTree
 15 {
 16     int ch[MAXNODE][SIGMA_SIZE];
 17     int f[MAXNODE];    // fail函数
 18     int val[MAXNODE];  // 每个字符串的结尾结点都有一个非0的val
 19     int last[MAXNODE]; // last[j]表示结点j沿着失配指针往回走时,遇到的下一个单词结点编号(后缀链接)
 20     int cnt[MAXS];
 21     int sz;
 22 
 23     void init()
 24     {
 25         sz = 1;
 26         memset(ch[0], 0, sizeof(ch[0]));
 27         memset(cnt, 0, sizeof(cnt));
 28         ms.clear();
 29     }
 30 
 31     // 字符c的编号
 32     int idx(char c)
 33     {
 34         return c - a;
 35     }
 36 
 37     // 插入字符串。v必须非0
 38     void insert(char *s, int v)
 39     {
 40         int u = 0, n = strlen(s);
 41         for (int i = 0; i < n; i++)
 42         {
 43             int c = idx(s[i]);
 44             if (!ch[u][c])
 45             {
 46                 memset(ch[sz], 0, sizeof(ch[sz]));
 47                 val[sz] = 0;
 48                 ch[u][c] = sz++;
 49             }
 50             u = ch[u][c];
 51         }
 52         val[u] = v;
 53         ms[string(s)] = v;
 54     }
 55 
 56     // 递归打印以结点j结尾的所有字符串
 57     void Cnt(int j)
 58     {
 59         if (j)
 60         {
 61             cnt[val[j]]++;
 62             Cnt(last[j]);
 63         }
 64     }
 65 
 66     // 在T中找模板
 67     int find(char* T)
 68     {
 69         int n = strlen(T);
 70         int j = 0; // 当前结点编号,初始为根结点
 71         for (int i = 0; i < n; i++)
 72         { // 文本串当前指针
 73             int c = idx(T[i]);
 74             while (j && !ch[j][c]) j = f[j]; // 顺着失配边走,直到可以匹配
 75             j = ch[j][c];
 76             if (val[j]) Cnt(j);
 77             else if (last[j]) Cnt(last[j]); // 找到了
 78         }
 79     }
 80 
 81     // 计算fail函数
 82     void getFail()
 83     {
 84         queue<int> q;
 85         f[0] = 0;
 86         // 初始化队列
 87         for (int c = 0; c < SIGMA_SIZE; c++)
 88         {
 89             int u = ch[0][c];
 90             if (u)
 91             {
 92                 f[u] = 0; q.push(u); last[u] = 0;
 93             }
 94         }
 95         // 按BFS顺序计算fail
 96         while (!q.empty())
 97         {
 98             int r = q.front(); q.pop();
 99             for (int c = 0; c < SIGMA_SIZE; c++)
100             {
101                 int u = ch[r][c];
102                 if (!u) continue;
103                 q.push(u);
104                 int v = f[r];
105                 while (v && !ch[v][c]) v = f[v];
106                 f[u] = ch[v][c];
107                 last[u] = val[f[u]] ? f[u] : last[f[u]];
108             }
109         }
110     }
111 
112 };
113 
114 ACTree ac;
115 char text[1000001], P[151][80];
116 int n, T;
117 
118 int main()
119 {
120     while (scanf("%d", &n) == 1 && n)
121     {
122         ac.init();
123         for (int i = 1; i <= n; i++)
124         {
125             scanf("%s", P[i]);
126             ac.insert(P[i], i);
127         }
128         ac.getFail();
129         scanf("%s",text);
130         ac.find(text);
131         int best = -1;
132         for (int i = 1; i <= n; i++)
133             if (ac.cnt[i] > best) best = ac.cnt[i];
134         printf("%d\n", best);
135         for (int i = 1; i <= n; i++)
136             if (ac.cnt[ms[string(P[i])]] == best) printf("%s\n", P[i]);
137         //不用ac.cnt[i]则是考虑模板串重复的情况,重复时后一个串会覆盖前一个串
138     }
139     return 0;
140 }
View Code

 

AC自动机

标签:后缀   ons   div   const   show   pre   ret   模板   clu   

原文地址:http://www.cnblogs.com/ivan-count/p/7498210.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!