HDU 2896 病毒侵袭 AC自动机
来源:互联网 发布:歌曲串烧制作软件 编辑:程序博客网 时间:2024/05/02 02:40
AC自动机模板题之一
可能我过几天就忘记了……
注意1:这题字符不是小写字母,是所有可见字符。
回忆:
* AC自动机,令g[i,j]表示从i到j这一路遍历的所有字符串。 f[i]的意义就是g[?,i]和g[0,f[i]]的字符串是相等的
* last[i] ,表示g[0,last[i]]的字符串,是确定存在的,并且以last[i]结尾的字符串
last的定义:
last[will] = val[f[will]] ? f[will] : last[f[will]];
这题是标准AC自动机模板
ac code:
#include<cstring>#include <cmath>#include <iostream>#include<queue>#include<cstdio>#include<map>#include<string>using namespace std;const int SIGMA_SIZE = 130;const int MAXNODE = 200 * 500 + 100;#define prln(x)cout<<#x<<" = "<<x<<endl#define pr(x)cout<<#x<<" = "<<x<<" "int n, m, X, Y;/* * AC自动机,令g[i,j]表示从i到j这一路遍历的所有字符串。 f[i]的意义就是g[?,i]和g[0,f[i]]的字符串是相等的 * last[i] ,表示g[0,last[i]]的字符串,是确定存在的,并且以last[i]结尾的字符串*/struct AhoCorasickAutomata {int ch[MAXNODE][SIGMA_SIZE];int f[MAXNODE]; // fail函数int val[MAXNODE]; // 每个字符串的结尾结点都有一个非0的valint last[MAXNODE]; // 输出链表的下一个结点int sz;queue<int>q;map<int,int>mp;int tot_web;void init() {sz = 1;memset(ch[0], 0, sizeof(ch[0]));memset(val, 0, sizeof(val));tot_web=0;}// 字符c的编号int idx(char c) { //if (c == '\0') return 62; /*if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'z') return c - 'a' + 10; return c - 'A' + 36; */return (int)c;} // 插入字符串。v必须非0void insert(char s[], int len, int id) {int now = 0;for(int i = 0; i < len; i++) {int c = idx(s[i]);if(!ch[now][c]) {memset(ch[sz], 0, sizeof(ch[sz]));val[sz] = 0;ch[now][c] = sz++;}now = ch[now][c];}val[now] = id;//单词出现的次数}// 递归打印以结点j结尾的所有字符串void print(int j) //输出j节点的信息,如果last[j]存在,last[j]的位置也有字符{if(j) {mp[val[j]]=1;print(last[j]);}}// 在T中找模板,text串的下标从0开始,长度为lenvoid find(char text[], int len, int id) {mp.clear();int j = 0; // 当前结点编号,初始为根结点for(int i = 0; i < len; i++) { // 文本串当前指针int c = idx(text[i]);//while(j && !ch[j][c]) j = f[j]; // 顺着细边走,直到可以匹配j = ch[j][c];if(val[j]) print(j);else if(last[j]) print(last[j]); // 找到了!}if (mp.size()){++tot_web;printf("web %d:", id);for (auto x : mp){printf(" %d", x.first);}printf("\n");}}//计算fail指针void get_fail(){f[0] = 0;//fail[i]表示,当匹配到某个位置失败,下一个自动的位置for (int c = 0; c < SIGMA_SIZE; c++){int will = ch[0][c];if (will){f[will]=0;q.push(will);last[will] = 0;}}while (!q.empty()){int now = q.front();//prln(now);q.pop();for (int c = 0; c < SIGMA_SIZE; ++ c){int will = ch[now][c];//now节点,想要访问的下标//if (!will)continue;//如果这个下标不存在,直接continue;if (!will){ch[now][c] = ch[f[now]][c];continue;}q.push(will);int pre = f[now];//失配指针,先指now的失配,至少有一段都是相等的while (pre && !ch[pre][c])pre = f[pre];//往前跳失配指针,类似 KMPf[will] = ch[pre][c];// f[i]的意义就是g[?,i]和g[0,f[i]]的字符串是相等的last[will] = val[f[will]] ? f[will] : last[f[will]];}}}void doit(){printf("total: %d\n", tot_web);// * 调试ac自动机数组信息用的/*for (int i = 0; i < sz; ++ i){prln(i);for (int j = 0; j < 26;++j){if (ch[i][j])cout<< ((char)(j+'a'))<<" "<<ch[i][j]<<endl;;}//cout<<endl;//cout<<endl;}for (int i = 0; i < sz; ++ i){pr(i),prln(val[i]);}for (int i = 0; i < sz; ++ i){pr(i),prln(f[i]);}for (int i = 0; i < sz; ++ i){pr(i),prln(last[i]);}*/}}ac;char text[100000];char pattern[510];int main() {while (~scanf("%d", &n)){ac.init();for (int i = 1; i <= n; ++ i){scanf("%s", pattern);//cout<<pattern<<endl;ac.insert(pattern, strlen(pattern), i);}ac.get_fail();scanf("%d", &m);for (int i = 1; i <= m; ++ i){scanf("%s", text);//cout<<text<<endl;ac.find(text, strlen(text), i);}ac.doit();}return 0;}
0 0
- HDU 2896 病毒侵袭 (AC自动机)
- hdu 2896 病毒侵袭 //AC自动机
- HDU 2896:病毒侵袭(AC自动机)
- hdu 2896 病毒侵袭 AC自动机
- HDU 2896 病毒侵袭(AC自动机)
- hdu 2896 病毒侵袭 AC自动机基础
- HDU 2896 病毒侵袭 AC自动机
- hdu 2896 病毒侵袭 -- AC自动机
- hdu 2896 病毒侵袭 (AC自动机)
- HDU 2896 病毒侵袭(AC 自动机)
- HDU 2896 病毒侵袭 (AC自动机)
- HDU 2896 病毒侵袭 【AC自动机】
- hdu 2896 病毒侵袭 AC自动机
- [HDU 2896]病毒侵袭[AC自动机]
- hdu 2896 病毒侵袭(AC自动机)
- hdu 2896 病毒侵袭(AC自动机)
- hdu 2896 病毒侵袭 (AC自动机)
- hdu 2896 病毒侵袭(AC自动机)
- 安装完 Android Studio 后启动,却报错
- oc学习之继承
- AsyncHttpClient Best Practice
- 第10期 8月刊《百炼成钢》
- automaticallyAdjustsScrollViewInsets
- HDU 2896 病毒侵袭 AC自动机
- Longest Increasing Subsequence
- 仿射密码
- 自定义dialog横向全屏,实现从右边进入,从底部掉落动画
- ImageView.ScaleType设置图解
- 带你读开源—ASP.NET_MVC(五)
- LDAP 管理用户(组)
- Windows 7 X64位平台下,VC6调试运行程序,中断调试无法退出
- 乘数密码