hdu 2896 病毒侵袭 ac自动机

/*
hdu 2896 病毒侵袭 ac自动机
从题意得知,模式串中没有重复的串出现,所以结构体中可以将last[](后缀链接)数组去掉
last[]数组主要是记录具有相同后缀模式串的末尾节点编号 。本题中主要是计算每一个模式串
在主串中有没有出现过,而不是计算出现过多少次,所以将last[]数组省掉....
*/
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 210*500
using namespace std;
class AC_atomata
{
public:
   int trie[N][128],  f[N], val[N];
   int vis[510];
   int nodeN;
   int total;
   queue<int>q;
   void init()
   {
      nodeN=0;
      val[0]=0;
      total=0;
      while(!q.empty()) q.pop();
      memset(trie[0], 0, sizeof(trie[0]));
   }
   void build(char *str, int index);//建立trie树
   void getFail();//失配函数
   void find(char *T, int n, int index);//查找函数
};

void AC_atomata::build(char *str, int index)
{
    int i, u;
    for(i=0, u=0; str[i]; ++i)
    {
        int ch=str[i];
        if(!trie[u][ch])
        {
            trie[u][ch]=++nodeN;
            memset(trie[nodeN], 0, sizeof(trie[nodeN]));
    }
    u=trie[u][ch];
    val[u]=0;
    }
    val[u]=index;
}

void AC_atomata::getFail()
{
   int r, u, v, i;
   f[0]=0;
   for(i=0; i<128; ++i)
   {
       if(trie[0][i])
       {
             q.push(trie[0][i]);
             f[trie[0][i]]=0;
       }
   }
   while(!q.empty())
   {
      r=q.front();
      q.pop();
      for(i=0; i<128; ++i)
      {
            u=trie[r][i];
            if(!u) continue;
            q.push(u);
            v=f[r];
            while(v && !trie[v][i]) v=trie[v][i];
            f[u]=trie[v][i];
      }
   }
}

void AC_atomata::find(char *T, int n, int index)
{
    int i, u;
    int cnt=0, v[3];
    memset(v, 0, sizeof(v));
    memset(vis, 0, sizeof(vis));//每一次查找将数组初始化,开始忘记初始化了, 哇了好多次
    for(i=0, u=0; T[i]; ++i)
    {
        int ch=T[i];
        while(u && !trie[u][ch])  u=f[u];
        u=trie[u][ch];
        if(val[u] && !vis[val[u]])
        {
            v[cnt++]=val[u];
            vis[val[u]]=1;
            if(cnt>2) break;
        }
    }
    if(cnt>0)
    {
        ++total;
        printf("web %d:", index);
        sort(v, v+3);
        for(i=0; i<3; ++i)
           if(v[i])  printf(" %d", v[i]);
        printf("\n");
    }
}

AC_atomata ac;
char T[10005], s[205];

int main()
{
   int n, m, i;
   while(scanf("%d", &n)!=EOF)
   {
       ac.init();
       for(i=1; i<=n; ++i)
        {
           scanf("%s", s);
           ac.build(s, i);
    }
       ac.getFail();
       scanf("%d", &m);
       for(i=1; i<=m; ++i)
       {
             scanf("%s", T);
             ac.find(T, n, i);
       }
       printf("total: %d\n", ac.total);
   }
   return 0;
}
/*
    上面的程序过了,感觉数据很水....
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 100005
#define M 505
using namespace std;
int n, m;
class AC_atomata
{
public:
    int trie[N][128], fail[N];
    int cnt;
    int vis[M];//标记边
    int nodeN;//节点数
    int val[N];//标记字符节点是否为单词末尾
    queue<int>q;
    void init();
    void build(char *T, int index) ;
    void getFail();
    void find(char *S, int index);
};

void AC_atomata:: init()
{
   while(!q.empty())  q.pop();
   memset(trie[0], 0, sizeof(trie[0]));
   nodeN=0;
   cnt=0;
   memset(val, 0, sizeof(val));
}

void AC_atomata:: build(char *T, int index)
{
    int i, u=0;
    for(i=0; T[i]; ++i)
    {
        if(trie[u][T[i]]==0)
        {
            trie[u][T[i]]=++nodeN;
            memset(trie[nodeN], 0, sizeof(trie[nodeN]));
    }
    val[u]=0;
    u=trie[u][T[i]];
    }
    val[u]=index;
}

void AC_atomata:: getFail()
{
    int r, u, v;
    int c, root=0;
    fail[root]=0;
    for(c=0; c<128; ++c)
    {
        if(v=trie[root][c])
        {
            fail[v]=root;
            q.push(v);
    }
    }
    while(!q.empty())
    {
        r=q.front(); q.pop();
    for(c=0; c<128; ++c)
    {
        u=trie[r][c];
        if(!u)//该节点不存在,也就是查找过程中每一个节点都是平等的
           trie[r][c]=trie[fail[r]][c];
        else
        {
            fail[u]=trie[fail[r]][c];
            q.push(u);
        }
    }
    }
} 

void AC_atomata:: find(char *S, int index)
{
   int cur, root, count=0;
   cur=root=0;
   memset(vis, 0, sizeof(vis));
   for(int i=0; S[i]; ++i)
   {
       cur=trie[cur][S[i]];
       int next=cur;

          //这个while循环就是last[]数组实现的功能,只不过是last[]数组记录的总是单词结尾字符的节点的编号
          //而我们通过沿着 next 节点的失配方向一直搜索, 也可以寻找到 以next节点所对应字符结尾的单词
       while(next!=root)
       {
              if(val[next])
                 {
              vis[val[next]]=1;
              count++;
          }
              next=fail[next];
       }
   }
   if(count>0)
   {
       ++cnt;
       printf("web %d:", index);
       for(int i=1; i<=n; ++i)
         if(vis[i])
           printf(" %d", i);
       printf("\n");
   }
} 

char t[205], s[10005];
AC_atomata ac;
int main()
{
   int i;
   while(scanf("%d", &n)!=EOF)
   {
       ac.init();
       for(i=1; i<=n; ++i)
       {
             scanf("%s", t);
             ac.build(t, i);
       }
       ac.getFail();
       scanf("%d", &m) ;
       for(i=1; i<=m; ++i)
       {
             scanf("%s", s);
             ac.find(s, i);
       }
       printf("total: %d\n", ac.cnt);
   }
   return 0;
}
时间: 2025-01-25 09:00:13

hdu 2896 病毒侵袭 ac自动机的相关文章

hdu 2896 病毒侵袭

点击此处即可传送到hdu 2896 //说点没有用的,这其实就是一个裸的AC自动机的模板题,我一开始什么都不会,这也是根据一个大牛的博客整的,在这条道路上还是太弱啊...... `病毒侵袭 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿啊~~ 但网路上总有那么些网站,开始借着民众的好奇心,打着介绍日食的旗号,大肆传播病毒.小t不幸成为受害

hdu 3065 病毒侵袭持续中

点击打开链接hdu 3065 思路:AC自动机模板 分析: 1 题目要求找出相应的字符串在源码串中出现的次数,并且告诉我们字符串只有大写字母.其实解法是一样的,只是别被大写字母这个给限制了,还是相当于建立trie,但是不能单建立大写字母的trie树. 2 当匹配到一个单词的时候就把单词对应的编号对应的个数加加. 代码 #include<iostream> #include<algorithm> #include<cstdio> #include<cstring&g

HDU 2222 AC自动机

题意:给出多组模式串,再给出一个母串,问多少模式串是母串的字串. 裸AC自动机题,来试模板的. #include <iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<queue> using namespace std; char key[55],des[1000005]; const int MAX_NODE = 1000005; const in

字典树+KMP+AC自动机

                                                 <<字典树模板>> 1:字典树,又称单词查找树,Trie树,是一种树形结构,哈希表的一个变种.用于统计,排序和保存大量的字符串(也可以保存其他的).优点就是利用公共的前缀来节约存储空间.在这举个简单的例子:比如说我们想储存3个单词,sky.skyline.skymoon.如果只是单纯的按照以前的字符数组存储的思路来存储的话,那么我们需要定义三个字符串数组.但是如果我们用字典树的话,只需

经典算法题每日演练——第八题 AC自动机

原文:经典算法题每日演练--第八题 AC自动机        上一篇我们说了单模式匹配算法KMP,现在我们有需求了,我要检查一篇文章中是否有某些敏感词,这其实就是多模式匹配的问题. 当然你也可以用KMP算法求出,那么它的时间复杂度为O(c*(m+n)),c:为模式串的个数.m:为模式串的长度,n:为正文的长度,那 么这个复杂度就不再是线性了,我们学算法就是希望能把要解决的问题优化到极致,这不,AC自动机就派上用场了.    其实AC自动机就是Trie树的一个活用,活用点就是灌输了kmp的思想,从

Aho-Corasick 多模式匹配算法、AC自动机详解

Aho-Corasick算法是多模式匹配中的经典算法,目前在实际应用中较多. Aho-Corasick算法对应的数据结构是Aho-Corasick自动机,简称AC自动机. 搞编程的一般都应该知道自动机FA吧,具体细分为:确定性有限状态自动机(DFA)和非确定性有限状态自动机NFA.普通的自动机不能进行多模式匹配,AC自动机增加了失败转移,转移到已经输入成功的文本的后缀,来实现. 1.多模式匹配 多模式匹配就是有多个模式串P1,P2,P3...,Pm,求出所有这些模式串在连续文本T1....n中的

HDU 2896 AC自动机

题意:给出多组模式串,再给出多组母串,输出存在于母串中模式串的编号. #include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int kind = 128; char str[10002],s[202]; int virus[10],vcnt; struct n

HDU 3065 AC自动机

题意:给出大写字母组成的模式串,再给出一个字串匹配,问每个模式串在母串中出现的次数,母串为可见字符ASCII. 注意字典树开next的大小,没看清题MLE好几次.. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int kind = 28; int num[1

新型Android病毒侵袭国内九大应用商店

有时我们看到国外某些病毒大肆侵袭,总为抱着侥幸心理,但现在一个新型Android病毒开始在国内蔓延.Mobile Market新的Android病毒代号为MMarketPay.A,用户感染之后 就会遭遇账单累计风险.此病毒已经蔓延至国内九家应用商店,包括N多网.机锋网. 应用汇.安丰网.3G门户.锋潮.机客.安卓4S店和中移动的Mobile Market,目前已有10万部手机受到感染.MMarketPay.A病毒能够通过自动完成在Mobile Market网站购买应用或者内容的流程,并通过Mob