病毒侵袭
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10281 Accepted Submission(s): 2670
Problem Description
当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻。。。。在这样的时刻,人们却异常兴奋——我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿啊~~
但网路上总有那么些网站,开始借着民众的好奇心,打着介绍日食的旗号,大肆传播病毒。小t不幸成为受害者之一。小t如此生气,他决定要把世界上所有带病毒的网站都找出来。当然,谁都知道这是不可能的。小t却执意要完成这不能的任务,他说:“子子孙孙无穷匮也!”(愚公后继有人了)。
万事开头难,小t收集了好多病毒的特征码,又收集了一批诡异网站的源码,他想知道这些网站中哪些是有病毒的,又是带了怎样的病毒呢?顺便还想知道他到底收集了多少带病毒的网站。这时候他却不知道何从下手了。所以想请大家帮帮忙。小t又是个急性子哦,所以解决问题越快越好哦~~
但网路上总有那么些网站,开始借着民众的好奇心,打着介绍日食的旗号,大肆传播病毒。小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码可见字符(不包括回车)。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在20—200之间。
每个病毒都有一个编号,依此为1—N。
不同编号的病毒特征码不会相同。
在这之后一行,有一个整数M(1<=M<=1000),表示网站数。
接下来M行,每行表示一个网站源码,源码字符串长度在7000—10000之间。
每个网站都有一个编号,依此为1—M。
以上字符串中字符都是ASCII码可见字符(不包括回车)。
Output
依次按如下格式输出按网站编号从小到大输出,带病毒的网站编号和包含病毒编号,每行一个含毒网站信息。
web 网站编号: 病毒编号 病毒编号 …
冒号后有一个空格,病毒编号按从小到大排列,两个病毒编号之间用一个空格隔开,如果一个网站包含病毒,病毒数不会超过3个。
最后一行输出统计信息,如下格式
total: 带病毒网站数
冒号后有一个空格。
web 网站编号: 病毒编号 病毒编号 …
冒号后有一个空格,病毒编号按从小到大排列,两个病毒编号之间用一个空格隔开,如果一个网站包含病毒,病毒数不会超过3个。
最后一行输出统计信息,如下格式
total: 带病毒网站数
冒号后有一个空格。
Sample Input
3 aaa bbb ccc 2 aaabbbccc bbaacc
Sample Output
web 1: 1 2 3 total: 1
Source
关于
shr
h
下面的版建树是这样的
黑线为字典树转移,红线为失败指针,蓝线为优化指针
整合版,加入节点转移优化,当一个节点为空时直接转移至fail节点
#define DeBUG
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <sstream>
#include <map>
#include <list>
#include <bitset>
using namespace std ;
#define zero {0}
#define INF 0x3f3f3f3f
#define EPS 1e-6
typedef long long LL;
const double PI = acos(-1.0);
//#pragma comment(linker, "/STACK:102400000,102400000")
inline int sgn(double x)
{
return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1);
}
#define N 100005
#define cha 128
#define TRUE true
#define FALSE false
#define Type int
bool used[510];
struct Trie
{
int next[N][cha];
int fail[N];
Type end[N];//用于存放目标节点数据
int Root, L;
int newnode()
{
for (int i = 0; i < cha; i++)
next[L][i] = -1;
end[L] = -1;//数据域
L++;
return L - 1;
}
void init()
{
L = 0;
Root = newnode();
}
void insert(char s[], int id)
{
int len = strlen(s);
int now = Root;
int ti;
for (int i = 0; i < len; i++)
{
ti = s[i];//ti下标
if (next[now][ti] == -1)
next[now][ti] = newnode();
now = next[now][ti];
}
end[now] = id;//数据域
}
void build()
{
queue<int>Q;
fail[Root] = Root;
for (int i = 0; i < cha; i++)
{
if (next[Root][i] == -1)
next[Root][i] = Root;
else
{
fail[next[Root][i]] = Root;
Q.push(next[Root][i]);
}
}
while (!Q.empty())
{
int now = Q.front();
Q.pop();
for (int i = 0; i < cha; i++)
{
if (next[now][i] == -1)
next[now][i] = next[fail[now]][i];
else
{
fail[next[now][i]] = next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
bool query(char buf[], int n)
{
int len = strlen(buf);
int now = Root;
int ti;
bool flag = false;
for (int i = 0; i < len; i++)
{
ti = buf[i];//ti下标
now = next[now][ti];
int temp = now;
while (temp != Root)
{
if (end[temp] != -1) //数据域
{
flag = true;
used[end[temp]] = TRUE;//数据域
}
temp = fail[temp];
}
}
return flag;
}
void debug()
{
for (int i = 0; i < L; i++)
{
printf("id = %3d, fail = %3d, end = %3d, \n", i, fail[i], end[i]);
// printf("word= [");
// for(int j=0;j<cha;j++)
// printf("%2c", j+'a');
// printf("]\n");
printf("chi = [");
for (int j = 0; j < cha; j++)
printf("%2d", next[i][j]);
printf("]\n\n");
}
}
};
char buf[10010];
Trie ac;
int main()
{
#ifdef DeBUGs
freopen("C:\\Users\\Sky\\Desktop\\1.in", "r", stdin);
#endif
int n, m;
while (scanf("%d", &n) + 1)
{
ac.init();
for (int i = 1; i <= n; i++)
{
scanf("%s", buf);
ac.insert(buf, i);
}
ac.build();
// ac.debug();
int ans = 0;
scanf("%d", &m);
for (int i = 1; i <= m; i++)
{
memset(used, 0, sizeof(used));
scanf("%s", buf);
if (ac.query(buf, n))
{
ans++;
printf("web %d:", i);
for (int j = 1; j <= n; j++)
{
if (used[j])
{
printf(" %d", j);
}
}
printf("\n");
}
}
printf("total: %d\n", ans);
}
return 0;
}
非整合版,常规建树
关于
shr
h
下面的版建树是这样的
#define DeBUG
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <sstream>
#include <map>
#include <list>
#include <bitset>
using namespace std ;
#define zero {0}
#define INF 0x3f3f3f3f
#define EPS 1e-6
typedef long long LL;
const double PI = acos(-1.0);
//#pragma comment(linker, "/STACK:102400000,102400000")
inline int sgn(double x)
{
return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1);
}
#define N 100005
#define Root 0
#define cha 129
struct node
{
int data;
int count;
int fail;
int next[cha];
};
node tree[N];
void init(node &a, int data)
{
a.data = data;
a.count = 0;
a.fail = Root;
for (int i = 0; i < cha; i++)
a.next[i] = -1;
}
int ID = 1;
void Insert(char s[], int id)
{
int p = Root;
for (int i = 0; s[i]; i++)
{
int data = s[i];
if (tree[p].next[data] == -1)
{
init(tree[ID], data);
tree[p].next[data] = ID;
ID++;
}
p = tree[p].next[data];
}
tree[p].count = id;
}
void AC_automation()
{
queue<node>Q;
Q.push(tree[Root]);
while (!Q.empty())
{
node now = Q.front();
Q.pop();
for (int j = 0; j < cha; j++)
{
if (now.next[j] != -1)
{
if (now.data == -1)
tree[now.next[j]].fail = Root;
else
{
int t = now.fail;
while (t != Root && tree[t].next[j] == -1)
{
t = tree[t].fail;
}
tree[now.next[j]].fail = max(tree[t].next[j], Root);
}
Q.push(tree[now.next[j]]);
}
}
}
}
bool is[1005];
int get_ans(char s[])
{
int p = Root, ans = 0;
for (int i = 0; s[i]; i++)
{
int t = s[i];
while (tree[p].next[t] == -1 && p)
{
p = tree[p].fail;
}
p = tree[p].next[t];
if (p == -1)
{
p = Root;
continue;
}
int j = p;
while (tree[j].count)
{
ans++;
is[tree[j].count] = 1;
j = tree[j].fail;
}
// 如果走到头以后当前字母不是关键字终点然而其fail指针指向字母是关键字终点的话,应当加入此关键值
if (tree[ tree[j].fail ].count)
{
ans++;
is[tree[ tree[j].fail ].count] = 1;
}
}
return ans;
}
char word[10005];
char code[10005];
int main()
{
#ifdef DeBUGs
freopen("C:\\Users\\Sky\\Desktop\\1.in", "r", stdin);
#endif
int n;
while (scanf("%d", &n) + 1)
{
int m;
init(tree[Root], -1);
for (int i = 1; i <= n; i++)
{
scanf("%s", word);
Insert(word, i);
}
AC_automation();
scanf("%d", &m);
int total = 0;
for (int j = 1; j <= m; j++)
{
memset(is, 0, sizeof(is));
scanf("%s", code);
int num = get_ans(code);
if (num != 0)
{
total++;
printf("web %d:", j);
for (int i = 1; i <= n; i++)
{
if (is[i])
{
printf(" %d", i);
}
}
printf("\n");
}
}
printf("total: %d\n", total);
}
return 0;
}