hdu-2896-病毒侵袭(AC自动机,两种实现)

来源:互联网 发布:淘宝网中年女羽绒服 编辑:程序博客网 时间:2024/06/06 20:23

题目传送门

题意不解释   ,由于是可见字符所以只用开到94个即可。AC自动机裸题。


指针实现code:(只能用C++提交 G++是64位指针会超内存)

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#define MAXN 94using namespace std;struct node{    int cut;    node *son[MAXN] ,*fail;    node(){        cut=0;        fail=NULL;        for(int i=0;i<MAXN;i++)            son[i]=NULL;    }};bool vis[510];node *root;void Insert(char *str,int x){    node *p=root;    int i=0;    while(str[i]!='\0'){        int id=str[i]-' ';        if(p->son[id]==NULL)            p->son[id]=new node;        p=p->son[id];        i++;    }    p->cut=x;}void fail_build(){    node *p=root;    queue<node *>q;    q.push(p);    while(!q.empty()){        p=q.front();        q.pop();        for(int i=0;i<MAXN;i++)        {            if(p->son[i]!=NULL)            {                if(p==root)                    p->son[i]->fail=root;                else                {                    node *temp=p->fail;                    while(temp!=NULL){                        if(temp->son[i]!=NULL){                            p->son[i]->fail=temp->son[i];                            break;                        }                        temp=temp->fail;                    }                    if(temp==NULL)                        p->son[i]->fail=root;                }                q.push(p->son[i]);            }        }    }}bool AC_find(char *str){    node *p=root;    bool falg=false;    int i=0;    while(str[i]!='\0'){        //printf("%d\n",i);        int id=str[i]-' ';        while(p->son[id]==NULL&&p!=root)            p=p->fail;        p=p->son[id];        if(p==NULL) p=root;        node *temp=p;        while(temp!=NULL&&temp->cut!=0){            vis[temp->cut]=true;            //temp->cut=-1;            temp=temp->fail;            falg=true;        }        i++;    }    return falg;}void del(node *p){    for(int i=0;i<MAXN;i++)        if(p->son[i]!=NULL)            del(p->son[i]);    delete(p);}int main(){    char str[10010],str1[210];    int n,m;    scanf("%d",&n);    root=new node;    for(int i=1;i<=n;i++){        scanf("%s",str1);        Insert(str1,i);    }    fail_build();    scanf("%d",&m);    int ans=0;    for(int i=1;i<=m;i++){        scanf("%s",str);        bool falg=0;        memset(vis,0,sizeof(vis));        if(AC_find(str)){ans++;falg=1;}        if(falg) printf("web %d:",i);        for(int i=0;i<=n;i++){            if(vis[i]) printf(" %d",i);        }        if(falg) printf("\n");    }    printf("total: %d\n",ans);    return 0;}

数组实现code:(数组实现,一维数组代表 节点个数)数组既节省时间也节省空间  但不太好理解 如何取舍自己看吧

#include <iostream>#include <stdio.h>#include <string.h>#include <queue>#include <algorithm>using namespace std;const int allSon = 130;    ///包含所有的字符const int maxn = 100005;int node[maxn][allSon];    ///字典树节点int fail[maxn];            ///fail指针int num[maxn];             ///num[i]代表以第i个节点为结尾的单词个数int vis[maxn];             ///标记int index[maxn];           ///用来存放模式串的编号char patten[maxn];         ///模式串char text[maxn];           ///文本串int ans[maxn];int id;                    ///用来给节点编号int total;                 ///统计总共有多少个网站感染病毒///将模式串插入到字典树,传入的模式串的编号void insertPatten(int identifier){    int p = 0;      ///指向根节点    int pos = 0;    ///下标    int len = strlen(patten);    while(pos < len)    {        int ch = patten[pos];        if(node[p][ch]==-1)     ///节点不存在        {            memset(node[id],-1,sizeof(node[id]));  ///孩子节点都置空            num[id] = 0;            fail[id] = -1;            vis[id] = -1;            node[p][ch] = id++;        }        p = node[p][ch];        pos++;    }    num[p]++;    index[p] = identifier;      ///存储编号}///找fail指针,构造AC自动机void build_AC_automaton(){    queue<int>qu;    int p = 0;          ///最开始指向根节点    qu.push(p);    while(!qu.empty())    {        p = qu.front();        qu.pop();        for(int i = 0; i < allSon; i++)        {            if(node[p][i]!=-1)  ///第i个孩子存在            {                if(p == 0)  ///如果p是根,根的孩子fail指向根                {                    fail[node[p][i]] = 0;                }                else                {                    int temp = fail[p];                    while(temp != -1)                    {                        if(node[temp][i] != -1)                        {                            fail[node[p][i]] = node[temp][i];                            break;                        }                        temp = fail[temp];                    }                    if(temp == -1)                    {                        fail[node[p][i]] = 0;                    }                }                qu.push(node[p][i]);            }        }    }}///在AC自动机中进行查询,传入参数是第i个网站的编号。void find_in_AC_automaton(int identify){    int p = 0;    int pos = 0;    int t = 0;    while(text[pos]!='\0')    {        int ch = text[pos];        while(node[p][ch]==-1 && p!=0)            p = fail[p];        p = node[p][ch];        if(p == -1) p = 0;        int temp = p;        /**由于别的字符串还要过来匹配,所以节点的num        值不能进行改变,我们可以用vis数组来实现标记,避免        重复统计**/        while(temp!=0 && vis[temp]!=identify)        {            vis[temp] = identify;            if(num[temp])   ///代表网站有一个病毒            {                ans[t++] = index[temp];            }            temp = fail[temp];        }        ///由于一个网站病毒最多三个,所以找够三个就出来,不要浪费时间做无用功。        if(t >= 3)            break;        pos++;    }    if(t != 0)    {        total++;        printf("web %d:",identify);        sort(ans,ans+t);        for(int i = 0; i < t; i++)            printf(" %d",ans[i]);        printf("\n");    }}void init(){     memset(node[0],-1,sizeof(node[0]));     num[0] = 0;     fail[0] = -1;     index[0] = -1;     vis[0] = -1;     id = 1;     total = 0;}int main(){    int N,M;    while(~scanf("%d",&N))    {        init();   ///初始化根节点        for(int i = 1; i <= N; i++)        {            scanf("%s",patten);            insertPatten(i);        }        build_AC_automaton();        scanf("%d",&M);        for(int i = 1; i <= M; i++)        {            scanf("%s",text);            find_in_AC_automaton(i);        }        printf("total: %d\n",total);    }    return 0;}