2016夏季练习——AC自动机

来源:HDU2896

注意中间需要判重,本来准备开一个vis数组的,但是后来发现MLE了,所以只好STL判重,注意在使用中实际上en数组赋值为了ID,从而减少了数组的开销,这是个灵活的地方

代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define STOP getchar();
using namespace std;
string str;
int n,m;
const int ALTN = 129;
const int MAXN = 2000005;
struct AC_machine{
    int nxt[MAXN][ALTN];
    int fail[MAXN];
    int en[MAXN];
    int root,L;
    int virus[1000];
    int cnt;
    int ID;
    //L是ID分配器
    int newnode(){
        for(int i=0;i<ALTN;i++)
            nxt[L][i]=-1;
        en[L++]=0;
        return L-1;
    }
    void ini(){
        L=0;
        ID=0;
        cnt=0;
        root = newnode();
    }
    void ini_v(){
        cnt=0;
        memset(virus,0,sizeof(virus));
    }
    void insert_in(string str){
        int len = str.length();
        int now = root;
        for(int i=0;i<len;i++){
            if(nxt[now][str[i]]==-1){
                nxt[now][str[i]]=newnode();
            }
            now = nxt[now][str[i]];
        }
        en[now]=++ID;
    }
    void build(){
        queue<int>Q;
        fail[root]=root;
        for(int i=0;i<ALTN;i++){
            if(nxt[root][i]==-1) nxt[root][i]=root;
            else {
                fail[nxt[root][i]]=root;
                Q.push(nxt[root][i]);
            }
        }
        while(!Q.empty()){
            int temp = Q.front();
            Q.pop();
            for(int i=0;i<ALTN;i++){
                if(nxt[temp][i]==-1) nxt[temp][i] = nxt[fail[temp]][i];
                else{
                    fail[nxt[temp][i]] = nxt[fail[temp]][i];
                    Q.push(nxt[temp][i]);
                }
            }
        }
    }
    int query(string str,int nc){
        int res=0;
        int len = str.length();
        int now=root;
        for(int i=0;i<len;i++){
            now = nxt[now][str[i]];
            int temp = now;
            while(temp!=root){
                if(en[temp]) {
                    virus[cnt++]=en[temp];
                    res++;
                }
                temp = fail[temp];
            }
        }
        if(!res) return 0;
        cout<<"web "<<nc<<":";
        sort(virus,virus+cnt);
        cnt = unique(virus,virus+cnt)-virus;
        for(int i=0;i<cnt;i++)
            cout<<" "<<virus[i];
        cout<<endl;
        return 1;
    }
}ac;
int main(){
    while(scanf("%d",&n)!=EOF){
        getchar();
        ac.ini();
        for(int i=0;i<n;i++){
            getline(cin,str);
            ac.insert_in(str);
        }
       // cout<<"successful insert!"<<endl;
        ac.build();
        scanf("%d",&m);
        getchar();
        int ans=0;
        for(int i=1;i<=m;i++){
            getline(cin,str);
            ac.ini_v();
            if(ac.query(str,i)) ans++;
        }
        cout<<"total: "<<ans<<endl;
    }

	return 0;
}
/*
3
aaa
bbb
ccc
4
aaabbbcccaaa
bbbaaccbbb
aaabbbccc
bbaacc
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值