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

Keywords Search HDU2222 AC自动机模板题

时间:2018-10-13 16:55:27      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:src   bfs   tmp   eps   open   图片   ==   NPU   pair   

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 }
View Code

 

Keywords Search HDU2222 AC自动机模板题

标签:src   bfs   tmp   eps   open   图片   ==   NPU   pair   

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

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