1. 程式人生 > >HDU 2222 Keywords Search (AC自動機模板題)

HDU 2222 Keywords Search (AC自動機模板題)

題目連結

題目大意

給多個模式串,求長串中出現多少次模式串。

分析

字串多模式匹配模板題,注意模式串有可能會有重複,用單詞標記陣列維護模板出現的次數,匹配時用一個標記陣列保證每個單詞結點只計算一次即可。

程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#define ls (rt<<1)
#define rs (rt<<1|1) #define bit(x) (1<<(x)) using namespace std; typedef long long LL; const double pi=4*atan(1.0); const int INF=0x3f3f3f3f; const double eps=1e-6; const int MAXN=1000010; const int MAX_NODE=500010; const int SIGMA_SIZE=26; struct AC_automation { int ch[MAX_NODE][SIGMA_SIZE];///Trie樹
int val[MAX_NODE];///單詞標記 int sz;///當前結點個數 int f[MAX_NODE];///失敗指標 int last[MAX_NODE]; bool vis[MAX_NODE]; int ans; void Init() { ans=0; sz=1; memset(ch[0],0,sizeof(ch[0])); val[0]=0; vis[0]=false; } void Insert(char *s) { int
n=strlen(s),u=0; for (int i=0;i<n;i++) { int id=s[i]-'a'; if (!ch[u][id]) { ch[u][id]=sz; memset(ch[sz],0,sizeof(ch[sz])); vis[sz]=false; val[sz++]=0; } u=ch[u][id]; } vis[u]=true; val[u]++; } void GetFail() { queue<int> Q; last[0]=f[0]=0; for (int i=0;i<SIGMA_SIZE;i++) { int u=ch[0][i]; if (u) { f[u]=last[u]=0; Q.push(u); } } while (!Q.empty()) { int r=Q.front();Q.pop(); for (int i=0;i<SIGMA_SIZE;i++) { int u=ch[r][i]; if (u==0) continue; Q.push(u); int v=f[r]; while (v&&ch[v][i]==0) v=f[v]; f[u]=ch[v][i]; last[u]=val[f[u]]?f[u]:last[f[u]]; } } } void Solve(int i) { if (!i) return; if (vis[i]) { ans+=val[i]; vis[i]=false; } Solve(last[i]); } void Find(char *T) { int n=strlen(T),j=0; for (int i=0;i<n;i++) { int id=T[i]-'a'; while (j&&ch[j][id]==0) j=f[j]; j=ch[j][id]; if (val[j]) Solve(j); else if (last[j]) Solve(last[j]); } } }; AC_automation ac; char P[60],T[1000010]; int main() { int Test,i,n; scanf("%d",&Test); while (Test--) { ac.Init(); scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%s",P); ac.Insert(P); } ac.GetFail(); scanf("%s",T); ac.Find(T); printf("%d\n",ac.ans); } return 0; } /* 1 5 she he say shr her yasherhs */