Keywords Search HDU2222 AC自动机模板题

ac自动机说起来很复杂,其实和kmp是一样的思路,都是寻找相同前后缀,减少跳的次数。只要理解了kmp是怎么求next数组的,ac自动机bfs甚至比knp还好写。

这里大致说一下kmp求next数组的方法吧,假设现在要求第c个字符的next值(假设这个c很大,这样画图出来比较清晰方便理解),因为遍历过程中我们已经知道了第c-1个字符的next为x(假设比c小很多),即next[c-1] = x。那就代表我们知道了a[1]—a[x]这一段和a[c-1-x]—a[c-1]这一段是相等的对吧。

那么现在有两种情况

一。a[x+1] 和 a[c]相等,那么显然变成了a[1]—a[x+1] 这一段和a[c-1-x]—a[c]这一段相等,即c位置的相同前后缀长度比c-1多了1,就是next[c-1]+1;

即原来是:

1——————————x      == c-1-x ————————————————c-1  ① 由于a[x+1] == a[c],变成了

1——————————x+1  == c-1-x——————————————————c

二。如果不相等,那么我们在1——x这一段下功夫,假设next[x] = y,即1——y == x-y——x这两段相等,注意根据①式,x-y——x == c-1-y——c-1,画个图就很清楚了,所以如果a[y+1] == a[c],那么相同前后缀长度就是y+1了。

即因为

1——————————x   ==    c-1-x————————————————c-1  

1——y    ==   x-y———x   ==    c-1-x——c-1-x+y     ==       c-1-y————c-1   由于a[y+1] == a[c],变成了

1——y+1             ==          c-1-y——————c

那如果a[y+1] 与a[c]还是不相等怎么办?其实细心的话应该发现这是一个递归过程了——只要再找next[y],循环上面的过程就可以了,想明白这个过程再去看求next数组的代码就很容易理解了。

最后还是上这道题代码:

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <set>
  6 #include <stack>
  7 #include <math.h>
  8 #include <string>
  9 #include <algorithm>
 10
 11 #define SIGMA_SIZE 26
 12 #define pii pair<int,int>
 13 #define lson rt<<1
 14 #define rson rt<<1|1
 15 #define lowbit(x) (x&-x)
 16 #define fode(i, a, b) for(int i=a; i>=b; i--)
 17 #define foe(i, a, b) for(int i=a; i<=b; i++)
 18 #define fod(i, a, b) for(int i=a; i>b; i--)
 19 #define fo(i, a, b) for(int i=a; i<b; i++)
 20 //#pragma warning ( disable : 4996 )
 21
 22 using namespace std;
 23 typedef long long LL;
 24 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 25 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 26 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 27 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 28 inline int Max(int a, int b) { return a>b ? a : b; }
 29 inline int Min(int a, int b) { return a>b ? b : a; }
 30 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 31 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 32 const LL INF = 0x3f3f3f3f3f3f3f3f;
 33 const LL lmod = 1e9+7;
 34 const int mod = 10000;
 35 const double eps = 1e-8;
 36 const int inf = 0x3f3f3f3f;
 37 const int maxk = 1e5+5;
 38 const int maxm = 510*510;
 39 const int maxn = 5e5+10;
 40
 41 struct node {
 42     node *fail, *s[26];
 43     int w;
 44     node() {}
 45
 46     void init() {
 47         fail = NULL;
 48         fo(i, 0, 26) s[i] = NULL;
 49         w = 0;
 50     }
 51 }*head;
 52
 53
 54 int n, ans;
 55 char str[1000010];
 56 queue<node*> q;
 57
 58 node* getfail(node* p, int x)
 59 {
 60     if (p->s[x] != NULL) return p->s[x];
 61     else {
 62         if (p == head) return head;
 63         else return getfail(p->fail, x);
 64     }
 65 }
 66
 67 void build()
 68 {
 69     node* root = head;
 70     node* tmp;
 71
 72     int len = strlen(str);
 73     for ( int j = 0; j < len; j++ )
 74     {
 75         int k = str[j]-‘a‘;
 76         if (root->s[k] == NULL) {
 77             tmp = new node; tmp->init();
 78             tmp->fail = head;
 79             root->s[k] = tmp;
 80         }
 81
 82         root = root->s[k];
 83         //标记单词结尾
 84         if (j == len-1) root->w++;
 85     }
 86 }
 87
 88 void build_ac()
 89 {
 90     node* r;
 91     while(!q.empty()) q.pop();
 92     q.push(head);
 93     while(!q.empty())
 94     {
 95         r = q.front(); q.pop();
 96         fo(j, 0, 26)
 97         {
 98             if (r->s[j] != NULL) {
 99                 q.push(r->s[j]);
100                 if (r == head) r->s[j]->fail = head;
101                 else r->s[j]->fail = getfail(r->fail, j);
102             }
103         }
104     }
105     return;
106 }
107
108 void solve()
109 {
110     int len = strlen(str);
111     node *tmp, *r = head;
112     fo(j, 0, len)
113     {
114         int k = str[j]-‘a‘;
115         //找到前缀
116         while( r->s[k]==NULL && r != head ) r = r->fail;
117         //自动机向下匹配
118         //如果可以匹配,则进入下一节点,否则返回头节点
119         r = (r->s[k]==NULL) ? head : r->s[k];
120         tmp = r;
121
122         //如果单词a出现,则他的前缀也全部出现过
123         while(tmp != head) {
124             ans += tmp->w;
125             tmp->w = 0;
126             tmp = tmp->fail;
127         }
128     }
129     return;
130 }
131
132
133
134 void init()
135 {
136     cin >> n; ans = 0;
137     head = new node, head->init();
138     foe(i, 1, n)
139         scanf("%s", str), build();
140
141     build_ac();
142     scanf("%s", str);
143 }
144
145 int main()
146 {
147
148     #ifndef ONLINE_JUDGE
149         freopen("input.txt", "r", stdin);
150     #endif
151
152     int t; cin >> t;
153     while(t--)
154     {
155         init();
156         solve();
157         printf("%d\n", ans);
158     }
159
160     return 0;
161 }

原文地址:https://www.cnblogs.com/chaoswr/p/9783281.html

时间: 2024-10-10 17:51:47

Keywords Search HDU2222 AC自动机模板题的相关文章

HDU-2222 Keywords Search(AC自动机--模板题)

题目大意:统计一共出现了多少次模板串. 题目分析:AC自动机的模板题.不过这题有坑,相同的模板串不能只算一次. 代码如下: # include<iostream> # include<cstdio> # include<queue> # include<map> # include<string> # include<cstring> # include<algorithm> using namespace std; co

HDU 2222 Keywords Search(AC自动机模板题)

题意:给出一个字符串和若干个模板,求出在文本串中出现的模板个数. 思路:因为有可能有重复的模板,trie树权值记录每个模板出现的次数即可. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map>

【HDU-2222】Keywords Search(AC自动机模板)

AC自动机的模板题,自己手敲了一遍模板. 添加失配边的时候,对每个结点的26条字母边链接的子结点扫一遍,如果结点存在,那么这个子结点的失配边就是主结点失配边对应结点链接的子节点. 如果结点不存在,那么这个结点就直接连到主结点失配边对应结点链接的子节点. 感觉AC自动机好难懂啊...QAQ 11885512 2014-10-16 16:22:43 Accepted 2222 687MS 26688K 2772 B G++ KinderRiven #include<stack> #include&

hdoj 2222 Keywords Search 【AC自动机 入门题】

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 44687    Accepted Submission(s): 14103 Problem Description In the modern time, Search engine came into the life of everybody li

HDU 2222:Keywords Search(AC自动机模板)

http://acm.hdu.edu.cn/showproblem.php?pid=2222 KMP是单模式串匹配的算法,而AC自动机是用于多模式串匹配的算法.主要由Trie和KMP的思想构成. 题意:输入N个模式串,再给出一个文本串,求文本串里出现的模式串数目. 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <al

Keywords Search (AC自动机模版题)

Problem Description In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.Wiskey also wants to bring this feature to his image retrieval system.Every image have a long description, when users type some keywords to

HDU 2222 Keywords Search(AC自动机模板题)

原题大意:原题链接 先给定T个单词,然后给定一个字符串,查询该字符串中包含多少个给定的单词 解题思路:AC自动机模板题 参考链接:哔哩哔哩算法讲堂 WA版本 注意:因为输入的单词可能有重复,那么Insert()函数中p->id=id;语句中p->id会被覆盖,在Query()函数中会一次性全部被清零,导致不能查询重复单词,以至于结果res错误. #include<queue> #include<cstdio> #include<cstring> using

LA 4670 出现次数最多的子串 (AC自动机模板题)

Dominating Patterns Time Limit:3000MS   Memory Limit:Unknown   64bit IO Format:%lld & %llu [Submit]  [Go Back]  [Status] Description The archaeologists are going to decipher a very mysterious ``language". Now, they know many language patterns; ea

hdu5384 AC自动机模板题,统计模式串在给定串中出现的个数

http://acm.hdu.edu.cn/showproblem.php?pid=5384 Problem Description Danganronpa is a video game franchise created and developed by Spike Chunsoft, the series' name is compounded from the Japanese words for "bullet" (dangan) and "refutation&q