模板_KMP和AC自动机

来源:互联网 发布:淘宝电子面单怎么申请 编辑:程序博客网 时间:2024/04/29 18:15

KMP

只贴下代码哈,资料网上很多的啦~

例题 POJ3461

#include <cstdio>#include <string>#include <cstring>using namespace std;const int maxn=1000010;char a[maxn],b[maxn];int next[maxn],la,lb;void build(){next[0]=0;for (int i=1,j=0;i<lb;i++){while (j!=0 && b[i]!=b[j])j = next[j-1];if (b[i]==b[j])j++;next[i] = j;}}void work(){int ans=0;for (int i=0,j=0;i<la;i++){while (j!=0 && a[i]!=b[j])j = next[j-1];if (a[i]==b[j]) j++;if (j == lb){++ans;j = next[j-1];}}printf("%d\n",ans);}int main(){int t;scanf("%d",&t);for (int i=0;i<t;i++){scanf("%s",b);scanf("%s",a);la = strlen(a);lb = strlen(b);build();work();}return 0;}

AC自动机

例题 HDU2222


无优化

insert:

先建字典树

pre:(按照BFS序进行)

失配点:i->fail=j表示j-i是1-i的最大后缀

沿着fa的失配点不断向上找,直到存在next[ch],则当前结点的失配点指向next[ch]。若不存在,则失配点指向root。

work:

扫主串,若不存在next[ch],就沿着fa的失配点不断向上找,直到存在next[ch]。每扫到一个结点,沿着失配点一直退到根节点。过程中,若当前结点有标记,则ans+=count。

#include <cstdio>#include <iostream>#include <cstring>#include <queue>using namespace std;const int maxn=1000010;char a[maxn],b[60];struct node{int count;node *fail,*next[26];node(){count = 0;fail = NULL;for (int i=0;i<26;i++)next[i] = NULL;}}*root;queue<node*> q;void insert(){node *p = root;int len = strlen(b),index;for (int i=0;i<len;i++){index = (int)b[i] - 97;if (p->next[index] == NULL)p->next[index] = new node();p = p->next[index];}p->count++;}void pre(){node *p,*temp;q.push(root);while (!q.empty()){p = q.front();q.pop();for (int i=0;i<26;i++)if (p->next[i] != NULL){temp = p->fail;while (temp != NULL){if (temp->next[i] != NULL){p->next[i]->fail = temp->next[i];break;}temp = temp->fail;}if (temp == NULL)p->next[i]->fail = root;q.push(p->next[i]);}}}void work(){node *p = root,*temp;int ans = 0,len = strlen(a),index;for (int i=0;i<len;i++){index = int(a[i]) - 97;while (p->next[index] == NULL && p != root)p = p->fail;p = p->next[index];if (p == NULL) p = root;temp = p;while (temp != root && temp->count != -1){ans += temp->count;temp->count = -1;temp = temp->fail;}}printf("%d\n",ans);}int main(){int t,n;scanf("%d",&t);for (int i=0;i<t;i++){root = new node();scanf("%d",&n);getchar();for (int j=0;j<n;j++){gets(b);insert();}pre();scanf("%s",a);work();}return 0;}

加优化

增加失配边(仍用next数组表示),就不需要一直回溯找失配点,只要找当前结点的失配边。

p->next[ch]即为p->fail->next[ch]。(失配边

p->next[i]->fail 即为 p->fail->next[i]。(失配点)

仍按照BFS序进行。

#include <cstdio>#include <iostream>#include <cstring>#include <queue>using namespace std;const int maxn=1000010;char a[maxn],b[60];struct node{int count;node *fail,*next[26];node(){count = 0;fail = NULL;for (int i=0;i<26;i++)next[i] = NULL;}}*root;queue<node*> q;void insert(){node *p = root;int len = strlen(b),index;for (int i=0;i<len;i++){index = (int)b[i] - 97;if (p->next[index] == NULL)p->next[index] = new node();p = p->next[index];}p->count++;}void pre(){node *p(root),*temp;for (int i=0;i<26;i++)if (p->next[i] != NULL){p->next[i]->fail = root;q.push(p->next[i]);}else p->next[i] = root;while (!q.empty()){p = q.front();q.pop();for (int i=0;i<26;i++)if (p->next[i] != NULL){p->next[i]->fail = p->fail->next[i];q.push(p->next[i]);}else p->next[i] = p->fail->next[i];}}void work(){node *p = root,*temp;int ans = 0,len = strlen(a),index;for (int i=0;i<len;i++){index = int(a[i]) - 97;p = p->next[index];if (p == NULL) p = root;temp = p;while (temp != root && temp->count != -1){ans += temp->count;temp->count = -1;temp = temp->fail;}}printf("%d\n",ans);}int main(){int t,n;scanf("%d",&t);for (int i=0;i<t;i++){root = new node();scanf("%d",&n);getchar();for (int j=0;j<n;j++){gets(b);insert();}pre();scanf("%s",a);work();}return 0;}


0 0
原创粉丝点击