HDU-3065(病毒侵袭持续中)

本文详细解析了一道AC自动机模板题,介绍了如何使用AC自动机进行字符串匹配,包括构建AC自动机、查找失败节点及查询单词出现次数的算法实现。
   题意不用多说,此题AC自动机模板题,考虑读者已经掌握了AC自动机,可以切这个题来巩固一下,
最坑的地方是多case题目居然没有说~!!!一直wa的同学们看看自己是不是用了多case。
题目原址:http://acm.hdu.edu.cn/showproblem.php?pid=3065
View Code
  1 //====================================================================
  2 //Name       :
  3 //Author     :hxf
  4 //copyright  :http://www.cnblogs.com/Free-rein/
  5 //Description:
  6 //Data       :2012.8.8
  7 //========================================================================
  8 #include<iostream>
  9 #include<algorithm>
 10 #include<stdio.h>
 11 #include<math.h>
 12 #include<string.h>
 13 #include<vector>
 14 #include<stack>
 15 #include<queue>
 16 #define MAX 100005
 17 #define inf 1499999999
 18 using namespace std;
 19 const int len=28;//最多只有26个英文字母
 20 struct Tril{
 21     Tril *fail;
 22     Tril *son[len];
 23     int count;
 24     Tril(){
 25         fail=NULL;
 26         count=0;
 27         memset(son,NULL,sizeof(son));
 28     }
 29 };
 30 char str[2000050];
 31 char word[1005][55];
 32 int ans[1005];
 33 void creat(char *word,Tril *root,int num)///////////插入tril树
 34 {
 35     Tril *p=root;
 36     int lenth=strlen(word);
 37     for(int i=0;i<lenth;i++)
 38     {
 39         int index=word[i]-'A';
 40         if(p->son[index]==NULL)
 41             p->son[index]=new Tril();
 42         p=p->son[index];
 43     }
 44     p->count=num;
 45 }
 46 void creat_ac_automation(Tril *root)/////寻找失败节点
 47 {
 48     queue<Tril *> q;
 49     root->fail = NULL;
 50     q.push(root);
 51     while (!q.empty()) {
 52         Tril * p_cur = q.front();
 53         q.pop();
 54         for (int i = 0; i < 26; ++i) {
 55             if (p_cur->son[i] != NULL) {
 56                 if (p_cur == root) {
 57                     p_cur->son[i]->fail = root;
 58                 } else {
 59                     Tril * temp = p_cur->fail;
 60                     while (temp != NULL) {
 61                         if (temp->son[i] != NULL) {
 62                             p_cur->son[i]->fail = temp->son[i];
 63                             break;
 64                         }
 65                         temp = temp->fail;
 66                     }
 67                     if (temp == NULL) {
 68                         p_cur->son[i]->fail = root;
 69                     }
 70                 }
 71                 q.push(p_cur->son[i]);
 72             }
 73         }
 74     }
 75 }
 76 void query(Tril *root)//从str字符串中查询word单词出现的个数
 77 {
 78     int lenth=strlen(str);
 79     Tril *p=root;
 80     for(int i=0;i<lenth;i++)
 81     {
 82         if(str[i]<'A'||str[i]>'Z')
 83         {
 84             p=root;
 85             continue;
 86         }
 87         int index=str[i]-'A';
 88         while(p->son[index]==NULL&&p!=root)
 89         {
 90             p=p->fail;
 91         }
 92         p=p->son[index];
 93         if(p==NULL)
 94             p=root;
 95         Tril *k=p;
 96         while(k!=root)
 97         {
 98             if(k->count>0)
 99             {
100                 int s=k->count;
101                 ans[s]++;
102             }
103             k=k->fail;
104         }
105     }
106 }
107 int main()
108 {
109     int n;
110     while(~scanf("%d", &n))
111     {
112         memset(ans,0,sizeof(ans));
113         Tril *root=new Tril();
114         scanf("%d",&n);
115         for(int i=1;i<=n;i++)
116         {
117             scanf("%s",word[i]);
118             getchar();
119             creat(word[i],root,i);
120         }
121         creat_ac_automation(root);
122         scanf("%s",str);
123         getchar();
124         query(root);
125         for(int i=1;i<=n;i++)
126         {
127             if(ans[i]>0)
128             {
129                 printf("%s: %d\n",word[i],ans[i]);
130             }
131         }
132     }
133     return 0;
134 }
 
  

 

 

转载于:https://www.cnblogs.com/Free-rein/archive/2012/08/09/2630136.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值