ac自动机俩模板

ac自动机算法正确性还没有理解,算法导论也看不懂。。等懂了回来发算法专题。

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 const int maxn=1e6+5;
 6 
 7 int n;
 8 char s[maxn];
 9 
10 class AC{
11 public:
12     struct node{
13         node *son[26], *fail;
14         int mark;
15     }root, *now, *nowson, *p;
16     AC(){}
17     void insert(char *s, int len){ //trie,没什么好说的
18         now=&root;
19         int v;
20         for (int i=0; i<len; ++i){
21             v=s[i]-'a';
22             if (!now->son[v]) now->son[v]=new node();
23             now=now->son[v];
24         }
25         ++now->mark;
26     }
27     void get_fail(){ //建立失败指针
28         int head=0, tail=1;
29         q[head]=&root;
30         while (head<tail){ //宽搜
31             now=q[head];
32             for (int i=0; i<26; ++i) //遍历每个儿子
33             if (now->son[i]){
34                 for (p=now->fail; p&&!p->son[i]; p=p->fail); //通过父亲来找失败指针
35                 //p是0,意味着连root都不行,那只能去root
36                 now->son[i]->fail=(p?p->son[i]:&root);
37                 q[tail++]=now->son[i];
38             } //else now->son[i]=now->fail->son[i]; //如果没有这个子节点,意味着肯定失配
39             ++head;
40         }
41     }
42     int count(char *s, int len){ //计算有多少个串出现
43         int ans=0;
44         now=&root;
45         int v;
46         for (int i=0; i<len; ++i){
47             //确定适配的树的结点位置
48             for (v=s[i]-'a'; now&&!now->son[v]; now=now->fail);
49             now=now?now->son[v]:&root; //如果一直到根还不匹配,那就跳到根
50             //对于一个匹配串的所有后缀检查
51             //如果这里ans没设置为-1,那就是求出现次数之和
52             for (p=now; p&&~p->mark; p=p->fail) {
53                 ans+=p->mark;
54                 p->mark=-1;
55             }
56         }
57         return ans;
58     }
59 private:
60     node *q[maxn], head, tail;
61 };
62 
63 AC ac;
64 
65 int main(){
66     scanf("%d", &n);
67     for (int i=0; i<n; ++i){
68         scanf("%s", s);
69         int t=strlen(s);
70         ac.insert(s, t);
71     }
72     ac.get_fail();
73     scanf("%s", s);
74     printf("%d
", ac.count(s, strlen(s)));
75     return 0;
76 }
  1 #include <cstdio>
  2 #include <cstring>
  3 using namespace std;
  4 
  5 const int maxn=155, maxl1=75, maxl2=1e6+5;
  6 
  7 int n, cnt, ans[maxn];
  8 char p[maxn][maxl1];
  9 char t[maxl2];
 10 
 11 struct node{
 12     node *son[26], *fail;
 13     int id, mark;
 14 }*mem[maxn*maxl1];
 15 class AC{
 16 public:
 17     node *root, *now, *nowson, *p;
 18     AC(){ root=new node(); }
 19     void fresh(){
 20         cnt=0;
 21         delete root;
 22         root=new node();
 23         for (int i=0; i<memlen; ++i) delete mem[i];
 24         memlen=0;
 25     }
 26     void insert(char *s, int len){ //trie,没什么好说的
 27         now=root;
 28         int v;
 29         for (int i=0; i<len; ++i){
 30             v=s[i]-'a';
 31             if (!now->son[v]) {
 32                 now->son[v]=new node();
 33                 mem[memlen++]=now->son[v];//内存回收表
 34             }
 35             now=now->son[v];
 36         }
 37         //如果不去重,这里写成等于1
 38         now->id=cnt++;
 39         ++now->mark;
 40     }
 41     void get_fail(){ //建立失败指针
 42         int head=0, tail=1;
 43         q[head]=root;
 44         while (head<tail){ //宽搜
 45             now=q[head];
 46             for (int i=0; i<26; ++i) //遍历每个儿子
 47             if (now->son[i]){
 48                 for (p=now->fail; p&&!p->son[i]; p=p->fail); //通过父亲来找失败指针
 49                 //p是0,意味着连root都不行,那只能去root
 50                 now->son[i]->fail=(p?p->son[i]:root);
 51                 q[tail++]=now->son[i];
 52             } //else now->son[i]=now->fail->son[i]; //如果没有这个子节点,意味着肯定失配
 53             ++head;
 54         }
 55     }
 56     void count(char *s, int len){ //计算有多少个串出现
 57         now=root;
 58         int v;
 59         for (int i=0; i<len; ++i){
 60             //确定适配的树的结点位置
 61             for (v=s[i]-'a'; now&&!now->son[v]; now=now->fail);
 62             now=now?now->son[v]:root; //如果一直到根还不匹配,那就跳到根
 63             //对于一个匹配串的所有后缀检查
 64             //如果这里ans没设置为-1,那就是求出现次数之和
 65             for (p=now; p&&~p->mark; p=p->fail) {
 66                 ans[p->id]+=p->mark;
 67                 //p->mark=-1;
 68             }
 69         }
 70     }
 71 private:
 72     node *q[maxn*maxl1]; //这里忘记加了
 73     int memlen;
 74 };
 75 
 76 AC ac;
 77 
 78 int main(){
 79     scanf("%d", &n);
 80     while (n){
 81         memset(ans, 0, sizeof(ans));
 82         for (int i=0; i<n; ++i){
 83             scanf("%s", p[i]);
 84             int t=strlen(p[i]);
 85             ac.insert(p[i], t);
 86         }
 87         ac.get_fail();
 88         scanf("%s", t);
 89         ac.count(t, strlen(t));
 90         int maxm=0;
 91         for (int i=0; i<n; ++i)
 92             if (ans[i]>maxm) maxm=ans[i];
 93         printf("%d
", maxm);
 94         for (int i=0; i<n; ++i)
 95             if (ans[i]==maxm) printf("%s
", p[i]);
 96         scanf("%d", &n);
 97         ac.fresh();
 98     }
 99     return 0;
100 }
原文地址:https://www.cnblogs.com/MyNameIsPc/p/7513545.html