AC自动机练习

时间:2023-02-13 17:45:58

目录

AC自动机

HDU 2896

指针写法(爆内存,MLE)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
#define mian main
#define ll long long
const int kind = 130;
string s;
struct node
{
    node *fail;       //失败指针
    node *next[kind]; //Tire每个节点的个子节点(最多个字母)
    int count;        //是否为该单词的最后一个节点
    int sum;
    node()            //构造函数初始化
    {
        fail=NULL;
        count=0;
        sum=0;
        memset(next,NULL,sizeof(next));
    }
}*q[501];          //队列,方便用于bfs构造失败指针
char str[10005];    //模式串
int head,tail;        //队列的头尾指针

void insert(string str,node *root,int id){
    node *p=root;
    int i=0,index;
    while(str[i])
    {
        index=str[i];
        if(p->next[index]==NULL) p->next[index]=new node();
        p=p->next[index];
        i++;
    }
    p->count++;     //在单词的最后一个节点count+1,代表一个单词
    p->sum=id;
}

void build_ac_automation(node *root){
    int i;
    root->fail=NULL;
    q[head++]=root;
    while(head!=tail)
    {
        node *temp=q[tail++];
        node *p=NULL;
        for(i=0; i<130; i++)
        {
            if(temp->next[i]!=NULL)
            {
                if(temp==root) temp->next[i]->fail=root;
                else
                {
                    p=temp->fail;
                    while(p!=NULL)
                    {
                        if(p->next[i]!=NULL)
                        {
                            temp->next[i]->fail=p->next[i];
                            break;
                        }
                        p=p->fail;
                    }
                    if(p==NULL) temp->next[i]->fail=root;
                }
                q[head++]=temp->next[i];
            }
        }
    }
}

int query(node *root,bool &flag,int id){
    int i=0,cnt=0,index,len=strlen(str);
    node *p=root;
    while(str[i])
    {
        index=str[i];
        while(p->next[index]==NULL && p!=root) p=p->fail;
        p=p->next[index];
        p=(p==NULL)?root:p;
        node *temp=p;
        while(temp!=root && temp->count!=-1)
        {
            cnt+=temp->count;
            if(temp->count>0){
                if(flag==true) cout<<"web "<<id<<": ";
                cout<<p->sum<<" ";
                flag=false;
            }
            temp->count=-1;
            temp=temp->fail;
        }
        i++;
    }
    return cnt;
}

int main()
{
    int n;
    int ca=0;
    while(cin>>n){
        ca++;
        node root;
        for(int i=1;i<=n;i++){
            cin>>s;
            insert(s,&root,i);
        }
        build_ac_automation(&root);
        int m;
        cin>>m;
        int ans=0;
        bool flag=true;
        for(int i=1;i<=m;i++){
            cin>>str;
            flag=true;
            if(query(&root,flag,i)!=0) ans++;
            if(flag==false) cout<<endl;
        }
        cout<<"total: "<<ans<<endl;
    }
    return 0;
}

数组写法(AC)

#include<bits/stdc++.h>
#define N 210*500
using namespace std;
queue<int>q;
struct Aho_Corasick_Automaton{
    int c[N][128],val[N],fail[N],cnt;
    void ins(char *s,int id){
        int len=strlen(s);int now=0;
        for(int i=0;i<len;i++){
            int v=s[i];
            if(!c[now][v])c[now][v]=++cnt;
            now=c[now][v];
        }
        val[now]=id;
    }
    void build(){
        for(int i=0;i<128;i++)if(c[0][i])fail[c[0][i]]=0,q.push(c[0][i]);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<128;i++)
            if(c[u][i])fail[c[u][i]]=c[fail[u]][i],q.push(c[u][i]);
            else c[u][i]=c[fail[u]][i];
        }
    }
    bool used[510];
    int query(char *s,int id,int n){
        bool flag=false;
        memset(used,false,sizeof(used));
        int len=strlen(s);int now=0,ans=0;
        for(int i=0;i<len;i++){
            now=c[now][s[i]];
            for(int t=now;t&&~val[t];t=fail[t]){
                if(val[t]!=0){
//                    cout<<val[t]<<endl;
                    used[val[t]]=true;//val[t]=-1;
                    flag=true;
                }
            }
        }
        if(flag==false) return false;
        printf("web %d:",id);
        for(int i=1;i<=n;i++){
            if(used[i]) cout<<" "<<i;
        }
        cout<<endl;
        return true;
    }
}AC;
int n;char p[1000005];
int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++)scanf("%s",p),AC.ins(p,i);
        AC.build();
        int m;
        cin>>m;
        int ans=0;
        for(int i=1;i<=m;i++){
            scanf("%s",p);
            if(AC.query(p,i,n)) ans++;
//            int ans=AC.query(p);
        }
        printf("total: %d\n",ans);
    }
    return 0;
}