hdu 2896 病毒入侵 AC自动机

来源:互联网 发布:fastboot刷zip软件 编辑:程序博客网 时间:2024/06/16 14:42

当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻。。。。在这样的时刻,人们却异常兴奋——我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿啊~~
但网路上总有那么些网站,开始借着民众的好奇心,打着介绍日食的旗号,大肆传播病毒。小t不幸成为受害者之一。小t如此生气,他决定要把世界上所有带病毒的网站都找出来。当然,谁都知道这是不可能的。小t却执意要完成这不能的任务,他说:“子子孙孙无穷匮也!”(愚公后继有人了)。
万事开头难,小t收集了好多病毒的特征码,又收集了一批诡异网站的源码,他想知道这些网站中哪些是有病毒的,又是带了怎样的病毒呢?顺便还想知道他到底收集了多少带病毒的网站。这时候他却不知道何从下手了。所以想请大家帮帮忙。小t又是个急性子哦,所以解决问题越快越好哦~~

Input
第一行,一个整数N(1<=N<=500),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在20—200之间。
每个病毒都有一个编号,依此为1—N。
不同编号的病毒特征码不会相同。
在这之后一行,有一个整数M(1<=M<=1000),表示网站数。
接下来M行,每行表示一个网站源码,源码字符串长度在7000—10000之间。
每个网站都有一个编号,依此为1—M。
以上字符串中字符都是ASCII码可见字符(不包括回车)。
Output
依次按如下格式输出按网站编号从小到大输出,带病毒的网站编号和包含病毒编号,每行一个含毒网站信息。
web 网站编号: 病毒编号 病毒编号 …
冒号后有一个空格,病毒编号按从小到大排列,两个病毒编号之间用一个空格隔开,如果一个网站包含病毒,病毒数不会超过3个。
最后一行输出统计信息,如下格式
total: 带病毒网站数
冒号后有一个空格。
Sample Input
3
aaa
bbb
ccc
2
aaabbbccc
bbaacc
Sample Output
web 1: 1 2 3
total: 1

ac 自动机模板吧 其实就改了个标记而已。。甚至标记都不用改。

#include <stdio.h>#include <stdlib.h>#include <algorithm>#include <vector>using namespace std;#define M 10010struct node{    int next[128];    int fail;    int sign;}t[M<<4];int q[M<<4],head=0,tail=1;int r[550],H=0,f[5],k,n,L=0;char str[220],s[M];vector<int> v;void Insert(char *a,int tot){    int i=0,p=0,j,x;    while(a[i])    {        x=t[p].next[a[i]];            if(x<0)            {                t[p].next[a[i]]=x=++L;                for(j=0;j<128;j++) t[x].next[j]=-1;                t[x].fail=-1;t[x].sign=0;                               }        p=x;        i++;    }    t[p].sign=tot;}void build_ACauto()//更新失配指针{    int i,p,x,y;    q[0]=0;    while(head<tail){        x=q[head++];        for(i=0;i<128;i++){            y=t[x].next[i];            if(y>=0){                if(x){                    p=t[x].fail;                    while(p>=0){                        if(t[p].next[i]>=0){                            t[y].fail=t[p].next[i];                            break;                        }                        p=t[p].fail;                    }                    if(p<0)t[y].fail=0;                }                else t[y].fail=0;                q[tail++]=y;            }        }    }}void ACauto()//启动AC自动机查找病毒串{    int i=0,p=0,x;    while(s[i]){        while(t[p].next[s[i]]<0&&p)p=t[p].fail;        p=t[p].next[s[i]];        if(p<0)p=0;        x=p;        while(x){            if(t[x].sign>0) v.push_back(t[x].sign);            x=t[x].fail;         }        i++;    }    //由于查找过程中将查过的点赋为H,会影响下个网站的搜索    //所以此处应将病毒串尾还原为其编号    // for(i=1;i<=n;i++)t[r[i]].sign=i;}int main(){    int i,j,m,sum=0;    scanf("%d",&n);    t[0].fail=-1;t[0].sign=0;    for(i=0;i<128;i++)t[0].next[i]=-1;    for(i=1;i<=n;i++){        scanf("%s",str);        Insert(str,i);    }    build_ACauto();    scanf("%d",&m);    for(i=1;i<=m;i++){        v.clear();        scanf("%s",s);        ACauto();        if(!v.size())continue;        printf("web %d:",i);        sort(v.begin(),v.end());        int kk=0;        printf(" %d",v[0] );        for(j=1;j<v.size()&&kk<3;j++)        {            if(v[j]!=v[j-1])            printf(" %d",v[j]),kk++;        }        puts("");        sum++;//累加病毒网站数    }    printf("total: %d\n",sum);    return 0;}

新板子写法

#include <bits/stdc++.h>using namespace std;const int maxn=200010;const int maxm=200010;const int SIGMA_SIZE=128;int n;vector<int> v;struct AC{    int ch[maxm][128];    int val[maxm];    int fail[maxm],last[maxm];    int sz;    void clear(){memset(ch[0],0,sizeof(ch[0]));sz=1;}    int idx(char x){return x;}    void insert(char *s,int id)    {        int u=0;        int n=strlen(s);        for(int i=0;i<n;i++)        {            int c=idx(s[i]);            if(!ch[u][c])            {                memset(ch[sz],0,sizeof(ch[sz]));                val[sz]=0;                ch[u][c]=sz++;            }            u=ch[u][c];        }        val[u]=id;    }    void getfail()    {        queue<int> q;        fail[0]=0;        int u=0;        for(int i=0;i<SIGMA_SIZE;i++)        {            u=ch[0][i];            if(u){q.push(u);fail[u]=0;last[u]=0;}        }        while(!q.empty())        {            int r=q.front();q.pop();            for(int i=0;i<SIGMA_SIZE;i++)            {                u=ch[r][i];                if(!u){ch[r][i]=ch[fail[r]][i];continue;}                q.push(u);                int v=fail[r];                while(v&&!ch[v][i])v=fail[v];                fail[u]=ch[v][i];                last[u]=val[fail[u]]?fail[u]:last[fail[u]];            }        }    }    int find(char *s)    {        int u=0,cnt=0;        for(int i=0;s[i];i++)        {            int c=idx(s[i]);            u=ch[u][c];            int temp=0;//必须赋初值为0,表示如果下面两个判断都不成立的时候while可以正常执行            if(val[u])                temp=u;            else if(last[u])                temp=last[u];            while(temp)            {                if(val[temp]>0)                v.push_back(val[temp]);                temp=last[temp];            }        }        return cnt;    }}tree;char str[220],s[10010];int main(){    int sum=0;    tree.clear();    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%s",str);        tree.insert(str,i);    }    tree.getfail();    int m;    scanf("%d",&m);    for(int i=1;i<=m;i++){        v.clear();        scanf("%s",s);        tree.find(s);        if(!v.size())continue;        printf("web %d:",i);        sort(v.begin(),v.end());        int kk=0;        printf(" %d",v[0] );        for(int j=1;j<v.size()&&kk<3;j++)        {            if(v[j]!=v[j-1])            printf(" %d",v[j]),kk++;        }        puts("");        sum++;//累加病毒网站数    }    printf("total: %d\n",sum );    return 0;}
0 0
原创粉丝点击