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\n", 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\n", maxm); 94 for (int i=0; i<n; ++i) 95 if (ans[i]==maxm) printf("%s\n", p[i]); 96 scanf("%d", &n); 97 ac.fresh(); 98 } 99 return 0; 100 }