病毒侵袭 HDU - 2896 板子题

当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻。。。。在这样的时刻,人们却异常兴奋——我们能在有生之年看到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自动机代码就完了,比起原板子题Keywords Search HDU - 2222就改了一点

AC自动机代码详解看Keywords Search HDU - 2222

 

代码:

  1 /*
  2 代码中:
  3 叶节点:代表此节点下没有子节点
  4 根节点:就是树的根
  5 子节点:就是这个节点的直接相连的节点(直系节点)
  6 
  7 此代码:
  8 用题目所给模式串构成一颗字典树
  9 然后找出来给出的待求串中每种模式串出现几次
 10 
 11 
 12 1.题目中的字符是除去回车的ASCII码可见字符(95个),我最开始定义的是以全部的ASCII码的个数(128)为基准的
 13 2.输出要排序后再输出
 14 */
 15 #include<stdio.h>
 16 #include<iostream>
 17 #include<string.h>
 18 #include<algorithm>
 19 #include<queue>
 20 using namespace std;
 21 const int maxn=30000000;
 22 typedef long long ll;
 23 int visit[maxn],length[1005];
 24 int v[1005][1005],n,m;
 25 struct Trie
 26 {
 27     int next[maxn/100][128],fail[maxn],ends[maxn];
 28     int root,L;
 29     int New_node() //创建一个新节点
 30     {
 31         for(int i=0; i<128; ++i)
 32         {
 33             next[L][i]=-1;
 34         }
 35         ends[L++]=0;
 36         return L-1;
 37     }
 38     void init()  //创建根节点
 39     {
 40         L=0;
 41         root=New_node();
 42     }
 43     void inserts(char s[],int x)  //往字典树里面插入新字符串
 44     {
 45         int len=strlen(s);
 46         int now=root;
 47         for(int i=0; i<len; ++i)
 48         {
 49             if(next[now][s[i]]==-1)
 50                 next[now][s[i]]=New_node();
 51             now=next[now][s[i]];
 52         }
 53         ends[now]=x;
 54     }
 55     void build()
 56     {
 57         queue<int>r;
 58         fail[root]=root;
 59         for(int i=0; i<128; ++i)
 60         {
 61             if(next[root][i]==-1)
 62             {
 63                 next[root][i]=root;
 64             }
 65             else
 66             {
 67                 fail[next[root][i]]=root;
 68                 r.push(next[root][i]);
 69             }
 70         }
 71         while(!r.empty())
 72         {
 73             int now=r.front();
 74             r.pop();
 75             for(int i=0; i<128; ++i)
 76             {
 77                 if(next[now][i]==-1)
 78                 {
 79                     next[now][i]=next[fail[now]][i];  //叶节点处没有设置失败节点而是往next上接了一段,这个时候
 80                     //这个fail里面的值已经在下面的else里面放过东西了
 81                 }
 82                 else
 83                 {
 84                     fail[next[now][i]]=next[fail[now]][i];  //此节点的子节点的失败节点就是此节点失败节点对应字符位置
 85                     r.push(next[now][i]);
 86                 }
 87             }
 88         }
 89     }
 90     void query(char s[],int x)
 91     {
 92         int len=strlen(s);
 93         int now=root;
 94         for(int i=0; i<len; ++i)
 95         {
 96             now=next[now][s[i]]; //这个now就保证了我们找的肯定是这个字符串中的一部分
 97             int temp=now; //这就是一直找,找到了就加1,找不到就通过失败节点看其他地方能不能找到
 98             while(temp!=root)
 99             {
100                 if(ends[temp] && !visit[temp])
101                 {
102                     visit[temp]=1;
103                     v[x][length[x]++]=ends[temp];
104                 }
105                 temp=fail[temp];
106             }
107         }
108     }
109 };
110 char s[maxn];
111 Trie ac;
112 void init()
113 {
114     for(int i=0; i<=ac.L; ++i)
115     {
116         visit[i]=0;
117     }
118     for(int i=1; i<=n; ++i)
119         length[i]=0;
120 }
121 
122 int main()
123 {
124     scanf("%d",&n);
125     ac.init();
126     for(int i=1; i<=n; ++i)
127     {
128         scanf("%s",s);
129         ac.inserts(s,i);
130     }
131     scanf("%d",&m);
132     ac.build();
133     int ans=0;
134     for(int i=1; i<=m; ++i)
135     {
136         init();
137         scanf("%s",s);
138         ac.query(s,i);
139         if(length[i])
140         {
141             ans++;
142             printf("web %d: ",i);
143             sort(v[i],v[i]+length[i]);  //之前是忘记加这个一直错,想的时候还知道要排序,写代码的时候就忘了
144             for(int j=0; j<length[i]; ++j)
145             {
146                 if(j!=length[i]-1) printf("%d ",v[i][j]);
147                 else printf("%d\n",v[i][j]);
148             }
149         }
150     }
151     printf("total: %d\n",ans);
152     return 0;
153 }

 

 

 

 

 

posted @ 2019-12-12 15:18  kongbursi  阅读(185)  评论(0编辑  收藏  举报