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表示1-j是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;
}