AC自己主动机

AC自己主动机是KMP和Trie的结合,主要处理多模板串匹配问题。以下推荐一个博客,有助于学习AC自己主动机。

这里另一个Kuangbin开的比赛,大家也能够做一下,加深对算法的理解。

以下是比赛中的题目,採用了notonlysuccess的模板。
HDU 2222 Keywords Search
题意:最裸的模板题,给定一些模板串以及一个文本串,要在文本串中找有多少个模板串。

/*
ID: wuqi9395@126.com
PROG:
LANG: C++
*/
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, n) for (int i = 0; i < n; i++)
#define debug puts("===============")
typedef long long ll;
using namespace std;
const int maxnode = 500100;
const int charset = 26;
struct ACAutomaton {
int ch[maxnode][charset];
int fail[maxnode];
int Q[maxnode];
int val[maxnode];
int sz;
int ID[128]; //初始化,计算字母相应的儿子ID,如:'a'->0 ... 'z'->25
void init() {
fail[0] = 0;
for (int i = 0; i < charset; i++) ID[i + 'a'] = i;
}
//又一次建树需先Reset
void reset() {
memset(ch[0], 0, sizeof(ch[0]));
sz = 1;
}
//将权值为key的字符串a插入到trie中
void Insert(char *s, int key) {
int u = 0;
for ( ; *s; s++) {
int c = ID[*s];
if (!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] += key;
}
//建立AC自己主动机,确定每一个节点的权值以及状态转移
void Construct () {
int *s = Q, *e = Q;
for (int i = 0; i < charset; i++) {
if (ch[0][i]) {
fail[ch[0][i]] = 0;
*e ++ = ch[0][i];
}
}
while(s != e) {
int u = *s++;
for (int i = 0; i < charset; i++) {
int &v = ch[u][i];
if (ch[u][i]) {
*e ++ = v;
fail[v] = ch[fail[u]][i];
} else {
v = ch[fail[u]][i];
}
}
}
}
//最基础的查询,询问一个字符串中出现了多少模板串
int query(char *s) {
int ans = 0, u = 0;
for ( ; *s; s++) {
int c = ID[*s];
u = ch[u][c];
int tmp = u;
while(tmp) {
ans += val[tmp];
val[tmp] = 0;
tmp = fail[tmp];
}
}
return ans;
}
}AC;
char str[1000100];
int main() {
AC.init();
int t, n;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
AC.reset();
for (int i = 0; i < n; i++) {
scanf("%s", str);
AC.Insert(str, 1);
}
AC.Construct();
scanf("%s", str);
printf("%d\n", AC.query(str));
}
return 0;
}

HDU 2896 病毒侵袭

题意:有N个病毒,M个文本串,问每一个文本串出现了多少个病毒,各自是哪些?一共同拥有多少个文本串出现了病毒?
思路:这道题的病毒能够包括全部可见ASC码值

/*
ID: wuqi9395@126.com
PROG:
LANG: C++
*/
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, n) for (int i = 0; i < n; i++)
#define debug puts("===============")
typedef long long ll;
using namespace std;
const int maxnode = 100100;
const int charset = 128;
struct ACAutomaton {
int ch[maxnode][charset];
int fail[maxnode];
int Q[maxnode];
int val[maxnode];
int sz;
int ID[128];
void init() {
fail[0] = 0;
for (int i = 0; i < charset; i++) ID[i] = i;
}
void reset() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
void Insert(char *s, int key) {
int u = 0;
for ( ; *s; s++) {
int c = ID[*s];
if (!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = key;
}
void Construct () {
int *s = Q, *e = Q;
for (int i = 0; i < charset; i++) {
if (ch[0][i]) {
*e++ = ch[0][i];
fail[ch[0][i]] = 0;
}
}
while(s != e) {
int u = *s++;
for (int i = 0; i < charset; i++) {
int &v = ch[u][i];
if (v) {
*e++ = v;
fail[v] = ch[fail[u]][i];
} else {
v = ch[fail[u]][i];
}
}
}
}
void query(char *s, int &tot, int id) {
int ans = 0, u = 0;
set<int> S;
set<int>::iterator it;
S.clear();
for (; *s; s++) {
int c = ID[*s];
u = ch[u][c];
int tmp = u;
while(tmp) {
if (val[tmp]) S.insert(val[tmp]), ans++;
tmp = fail[tmp];
}
}
if (ans) {
printf("web %d:", id);
for (it = S.begin(); it != S.end(); it++) printf(" %d", *it);
putchar('\n');
tot++;
}
}
}AC;
char buf[210], str[10100];
int main () {
int n, m, tot = 0;
scanf("%d", &n);
AC.init();
AC.reset();
for (int i = 0; i < n; i++) {
scanf("%s", buf);
AC.Insert(buf, i + 1);
}
AC.Construct();
scanf("%d", &m);
for (int i = 0; i < m; i++) {
scanf("%s", str);
AC.query(str, tot, i + 1);
}
printf("total: %d\n", tot);
return 0;
}

HDU 3065 病毒侵袭持续中

题意:有N个病毒,一个文本串,问文本串中每一个病毒出现了多少次
思路:也是基础的模板,是多case。。

/*
ID: wuqi9395@126.com
PROG:
LANG: C++
*/
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, n) for (int i = 0; i < n; i++)
#define debug puts("===============")
typedef long long ll;
using namespace std;
const int maxnode = 50010;
const int charset = 128;
int cnt[1100];
struct ACAutomaton {
int ch[maxnode][charset];
int fail[maxnode];
int Q[maxnode];
int val[maxnode];
int sz;
int ID[128];
void init() {
fail[0] = 0;
for (int i = 0; i < charset; i++) ID[i] = i;
}
void reset() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
void Insert(char *s, int key) {
int u = 0;
for ( ; *s; s++) {
int c = ID[*s];
if (!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = key;
}
void Construct () {
int *s = Q, *e = Q;
for (int i = 0; i < charset; i++) {
if (ch[0][i]) {
*e++ = ch[0][i];
fail[ch[0][i]] = 0;
}
}
while(s != e) {
int u = *s++;
for (int i = 0; i < charset; i++) {
int &v = ch[u][i];
if (v) {
*e++ = v;
fail[v] = ch[fail[u]][i];
} else {
v = ch[fail[u]][i];
}
}
}
}
void query(char *s) {
int u = 0;
for (; *s; s++) {
int c = ID[*s];
u = ch[u][c];
int tmp = u;
while(tmp) {
if (val[tmp]) cnt[val[tmp]]++;
tmp = fail[tmp];
}
}
}
} AC;
char buf[1100][55], str[2000100];
int main () {
int n, m, tot = 0;
AC.init();
while(~scanf("%d", &n)) {
AC.reset();
for (int i = 0; i < n; i++) {
scanf("%s", buf[i]);
AC.Insert(buf[i], i + 1);
cnt[i + 1] = 0;
}
AC.Construct();
scanf("%s", str);
AC.query(str);
for (int i = 1; i <= n; i++) if (cnt[i]) printf("%s: %d\n", buf[i - 1], cnt[i]);
}
return 0;
}

ZOJ 3430 Detect the Virus

题意:有一种编码方式,将输进来的字符转化为二进制,然后6个为一组,不足补零,得到一个新的数字,每一个数字相应一个字符(见题面)。如今给你已经编码过的n个病毒,和m个编码过的文本串,问每一个文本串各包括多少种病毒。
思路:这里反编码的时候,会发现可能有256种状态,所以不能用字符串表示。反编码之后就是裸的AC自己主动机。
/*
ID: wuqi9395@126.com
PROG:
LANG: C++
*/
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, n) for (int i = 0; i < n; i++)
#define debug puts("===============")
typedef long long ll;
using namespace std;
const int maxnode = 510 * 64;
const int charset = 256;
struct ACAutomaton {
int ch[maxnode][charset];
int fail[maxnode];
int Q[maxnode];
int val[maxnode];
int sz;
int ID[256];
void init() {
fail[0] = 0;
//for (int i = 0; i < charset; i++) ID[i] = i;
}
void reset() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
void Insert(unsigned char s[], int key, int len) {
int u = 0;
for (int i = 0; i < len; i++) {
int c = s[i];
if (!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = key;
}
void Construct () {
int *s = Q, *e = Q;
for (int i = 0; i < charset; i++) {
if (ch[0][i]) {
*e++ = ch[0][i];
fail[ch[0][i]] = 0;
}
}
while(s != e) {
int u = *s++;
for (int i = 0; i < charset; i++) {
int &v = ch[u][i];
if (v) {
*e++ = v;
fail[v] = ch[fail[u]][i];
} else {
v = ch[fail[u]][i];
}
}
}
}
void query(unsigned char s[], int len) {
int u = 0, ans = 0;
bool vis[520] = {0};
for (int i = 0; i < len; i++) {
int c = s[i];
u = ch[u][c];
int tmp = u;
while(tmp) {
if (val[tmp] && !vis[val[tmp]]) {
ans++, vis[val[tmp]] = 1;
}
tmp = fail[tmp];
}
}
printf("%d\n", ans);
}
} AC;
char s[4000];
unsigned char g[4000];
unsigned char now[4000];
void get(char *s, int len) {
for (int i = 0; i < len; i++) {
if (s[i] >= 'A' && s[i] <= 'Z') g[i] = s[i] - 'A';
else if (s[i] >= 'a' && s[i] <= 'z') g[i] = s[i] - 'a' + 26;
else if (s[i] >= '0' && s[i] <= '9') g[i] = s[i] - '0' + 52;
else if (s[i] == '+') g[i] = 62;
else g[i] = 63;
}
g[len] = 0;
}
int change(unsigned char g[], int len) {
int cnt = 0;
for (int i = 0; i < len; i += 4) {
now[cnt++] = (g[i] << 2) | (g[i + 1] >> 4);
if (i + 2 < len) now[cnt++] = (g[i + 1] << 4) | (g[i + 2] >> 2);
if (i + 3 < len) now[cnt++] = (g[i + 2] << 6) | g[i + 3];
}
return cnt;
}
int main () {
int n, m;
AC.init();
while(~scanf("%d", &n)) {
AC.reset();
for (int i = 0; i < n; i++) {
scanf("%s", s);
int len = strlen(s);
while(s[len - 1] == '=') len--;
get(s, len);
int cnt = change(g, len);
AC.Insert(now, i + 1, cnt);
}
AC.Construct();
scanf("%d", &m);
while(m--) {
scanf("%s", s);
int len = strlen(s);
while(s[len - 1] == '=') len--;
get(s, len);
int cnt = change(g, len);
AC.query(now, cnt);
}
putchar('\n');
}
return 0;
}

POJ 2778 DNA Sequence

题意:DNA的序列由ACTG四个字母组成,如今给定m个不可行的序列。问随机构成的长度为n的序列中,有多少种序列是可行的(仅仅要包括一个不可行序列便不可行)。个数非常大,对100000取模。 

思路:AC自己主动机 + DP 解题报告

HDU 2243 考研路茫茫――单词情结
题意:给定一些词根,假设一个单词包括有词根,则觉得是有效的。如今问长度不超过L的单词里面,有多少有效的单词?

ZOJ 2619 Generator
题意:给定一个数N,代表能够选前N个字母。然后给定一个仅有前N个字母组成的字符串,问从空串開始构造,每次能够在已有基础上从前N个字母中挑选一个加在后面,问构造的字符串的长度期望是多少?



持续更新中


AC自己主动机的更多相关文章

  1. POJ 2778 DNA Sequence (AC自己主动机 + dp)

    DNA Sequence 题意:DNA的序列由ACTG四个字母组成,如今给定m个不可行的序列.问随机构成的长度为n的序列中.有多少种序列是可行的(仅仅要包括一个不可行序列便不可行).个数非常大.对10 ...

  2. hdu 2222 Keywords Search ac自己主动机

    点击打开链接题目链接 Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Ja ...

  3. 【UVA】1449-Dominating Patterns(AC自己主动机)

    AC自己主动机的模板题.须要注意的是,对于每一个字符串,须要利用map将它映射到一个结点上,这样才干按顺序输出结果. 14360841 1449 option=com_onlinejudge& ...

  4. POJ 3691 &amp; HDU 2457 DNA repair (AC自己主动机,DP)

    http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: ...

  5. HDU 2896 病毒侵袭 AC自己主动机题解

    本题是在text里面查找key word的增强版.由于这里有多个text. 那么就不能够简单把Trie的叶子标志记录改动成-1进行加速了,能够使用其它技术.我直接使用个vis数组记录已经訪问过的节点, ...

  6. NYOJ 1085 数单词 (AC自己主动机模板题)

    数单词 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描写叙述 为了可以顺利通过英语四六级考试,如今大家每天早上都会早起读英语. LYH本来以为自己在6月份的考试中能够通过六 ...

  7. hdu 4057 AC自己主动机+状态压缩dp

    http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes r ...

  8. Keywords Search (ac 自己主动机)

    Keywords Search Problem Description In the modern time, Search engine came into the life of everybod ...

  9. HDU - 2825 Wireless Password(AC自己主动机+DP)

    Description Liyuan lives in a old apartment. One day, he suddenly found that there was a wireless ne ...

  10. Hdu 3341 Lost&#39;s revenge (ac+自己主动机dp+hash)

    标题效果: 举个很多种DNA弦,每个字符串值值至1.最后,一个长字符串.要安排你最后一次另一个字符串,使其没事子值和最大. IDEAS: 首先easy我们的想法是想搜索的!管她3721..直接一个字符 ...

随机推荐

  1. OCA读书笔记(13) - 性能管理

    使用EM监控性能使用自动内存管理(AMM)使用Memory Advisor分配内存查看性能相关动态视图诊断无效的和不可用的对象 创建问题SQLsqlplus / as sysdbaconn scott ...

  2. Company Story | Vistaprint

    Company Story | Vistaprint Company Story A Gap in the Small Business Marketplace It’s rare that a hi ...

  3. Wamp环境下配置--Apache虚拟主机

    1.首先打开apache的配置文件httpd.conf,并去掉#Include conf/extra/httpd-vhosts.conf前面的#,启用虚拟主机功能 # Virtual hosts In ...

  4. oracle动态注冊參数local_listener

    local_listener參数有两种书写格式,提供了不同的功能. 监听文件上,1521和1526port上都有动态监听port. [oracle@dbsv admin]$ cat listener. ...

  5. Android的编译系统

    一.Makefile的主要流程   以下主要流程都在build/core/main.mk里安排.   l  初始化相关的参数设置(buildspec.mk.envsetup.mk.config.mk) ...

  6. MFC中模态对话框和非模态对话框的差别

    在MFC中有模态对话框和非模态对话框,那这两种有什么差别呢. 又都是用于什么场合呢. 首先,要弄清楚2种对话框是怎样创建的. 然后要弄清楚2种对话框有什么差别,可能从表面上看,模态会堵塞主对话框.可原 ...

  7. linux中怎样设置DHCP

    linux怎样设置DHCP 环境:RH linux 9.0 使用linux下经常使用的dhcpd包. 最新版本号 dhcp3.0.5 下载地址: 下载 1.安装: 先拷贝dhcp-3.0.5.tar. ...

  8. java它们的定义ArrayList序列, 大神跳跃

    一个list有两种类型的对象,今天有需求必须责令不同的约会对象,这里是代码 /** *@author xh1991101@163.com */ List<Message> messages ...

  9. poj1236 有向图加边变成强连通图

    给我们一个有向图,有两个问题 1.最少要给多少个点发消息,才能使得所有的点都收到消息(消息可以随边传递) 2.最少需要多少条边才能使得图变成强连通图 对于一个强连通分量,可以当做一个点来考虑,所以我们 ...

  10. hdu1513 (滚动数据压缩空间)

    给定一个字符串,问最少添加多少个字符可以使得这个字符串变成回文串 if(str[i]==str[j]) dp[i][j] = dp[i+1][j-1] else dp[i][j] = min(dp[i ...