1. 程式人生 > >Keywords Search HDU2222 AC自動機模板題

Keywords Search HDU2222 AC自動機模板題

type pop class 都是 head gcd rds cst ons

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自動機模板題