/*
啥也不说了,直接套模板。。。
*/
1 #include<iostream>
#include<map>
#include<string>
#include<cstring>
#include<queue>
#define N 500000
using namespace std; class AC_Atomata
{
public:
int nodeN;//trie树的节点个数
int trie[N][];//trie树
int f[N];//失配函数
//map<string, int>ms;//字符串到字符串编号的映射,防止出现多个字符串的模板
int last[N];// last[j]表示节点j沿着失配指针往回走时遇到的下一个单词节点的编号
int cnt;//最多在主串中出现的单词数
int val[N];//标记该节点是否为字符串的端点,该题中val[j]表示以节点j所对应的字符所结束的相同字符串的个数
int vis[N];//标记该节点已经访问过了
queue<int>q;
void init();
void buildTrie(char *p);
void getFail();
void find(char *T);
void countWords(int k);
}; void AC_Atomata::init()
{
nodeN=;
ms.clear();
memset(vis, , sizeof(vis));
memset(trie[], , sizeof(trie[]));
//memset(cnt, 0, sizeof(cnt));
cnt=;
} void AC_Atomata::buildTrie(char *p)
{
int i, u=;
for(i=; p[i]; ++i)
{
int k=p[i]-'a';
if(!trie[u][k])
{
memset(trie[nodeN+], , sizeof(trie[nodeN+])) ;
trie[u][k]=++nodeN;
val[nodeN]=;
}
u=trie[u][k];
}
++val[u];
//ms[string(p)]=v;
} void AC_Atomata::getFail()
{
int u, v, r, c;
while(!q.empty()) q.pop();
f[]=;
for(c=; c<; ++c)
{
u=trie[][c];
if(u)
{
f[u]=;
q.push(u);
last[u]=;
}
}
while(!q.empty())
{
r=q.front();
q.pop();
for(c=; c<; ++c)
{
u=trie[r][c];
if(!u) continue;
q.push(u);
v=f[r];
while(v && !trie[v][c]) v=f[v];
f[u]=trie[v][c];
last[u]=val[f[u]] ? f[u] : last[f[u]];
}
}
} void AC_Atomata::countWords(int k)
{
if(k && !vis[k])
{
//++cnt[val[k]];//k就是该单词所对应的最后一个字符的节点编号,val[k]是这个单词再输入时候的编号
vis[k]=;//表示以该节点结束的字符串已经访问过了,如果主串中再出现该字符串则不会再计算在内
cnt+=val[k];//
countWords(last[k]);
}
} void AC_Atomata::find(char *T)
{
int i, j;
for(i=, j=; T[i]; ++i)
{
int c=T[i]-'a';
while(j && !trie[j][c]) j=f[j];//一直找到可以匹配的字符节点
j=trie[j][c];
if(val[j])//单词的最后一个字符
countWords(j);
else if(last[j])//如果不是某个单词的最后一个节点
countWords(last[j]);
}
} AC_Atomata ac; char T[];
char s[]; int main()
{
int t, n, i;
scanf("%d", &t);
while(t--)
{
ac.init();
scanf("%d", &n);
for(i=; i<=n; ++i)
{
scanf("%s", s);
ac.buildTrie(s);
}
scanf("%s", T);
ac.getFail();
ac.find(T);
printf("%d\n", ac.cnt);
}
return ;
}
  /*
咱再换一种方式来写,赶脚这种方式更靠谱一些!
*/
1 #include<queue>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#define N 500000
using namespace std; class TRIE
{
public:
int ch[];//建立trie树的孩子节点个数
int val;//标记该节点是否是单词的结束节点
int fail;//该节点失配时要移向的节点的编号
int last;//后缀连接,示节该点沿着失配指针往回走时遇到的下一个单词节点的编号
int vis;//标记以该点字符所结束的字符串是否已经访问过了
}; class AC_Atomata
{
public:
TRIE trie[N];//建立节点
int nodeN;//trie树的节点的个数
int cnt;//记录节点单词在主串出现的次数
AC_Atomata()
{
nodeN=;
cnt=;
trie[].val=trie[].vis=;
memset(trie[].ch, , sizeof(trie[].ch));
while(!q.empty()) q.pop();
}
queue<int>q;
void buildTrie(char *p);
void getFail();
void find(char *T);
void countWords(int k);
}; void AC_Atomata::buildTrie(char *p)
{
int i, u;
for(i=, u=; p[i]; ++i)
{
int k=p[i]-'a';
if(!trie[u].ch[k])
{
trie[u].ch[k]=++nodeN;
memset(trie[nodeN].ch, , sizeof(trie[nodeN].ch));
trie[nodeN].val=trie[nodeN].vis=;
}
u=trie[u].ch[k];
}
++trie[u].val;
} void AC_Atomata::getFail()
{
int r, u, v, c;
trie[].fail=;
for(c=; c<; ++c)
{
u=trie[].ch[c];
if(u)
{
q.push(u);
trie[u].fail=;
trie[u].last=;
}
}
while(!q.empty())
{
r=q.front();
q.pop();
for(c=; c<; ++c)
{
u=trie[r].ch[c];
if(!u) continue;
q.push(u);
v=trie[r].fail;
while(v && !trie[v].ch[c]) v=trie[v].fail;
v=trie[v].ch[c];//v 节点就是在沿着失配指针往回走时遇到的下一个单词某个字符节点的编号
trie[u].fail=v;
trie[u].last=trie[v].val ? v : trie[v].last;//last记录的总是一个完整的单词最后一个字符节点的编号
}
}
} void AC_Atomata:: find(char *T)
{
int i, j;
for(i=, j=; T[i]; ++i)
{
int k=T[i]-'a';
while(j && !trie[j].ch[k]) j=trie[j].fail;
j=trie[j].ch[k];
if(trie[j].val)
countWords(j);
else if(trie[j].last)
countWords(trie[j].last);
}
} void AC_Atomata::countWords(int n)
{
if(n && !trie[n].vis)
{
trie[n].vis=;
cnt+=trie[n].val;
countWords(trie[n].last);
}
} AC_Atomata ac;
char T[];
char s[]; int main()
{
int t, n;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
for(int i=; i<=n; ++i)
{
scanf("%s", s);
ac.buildTrie(s);
}
scanf("%s", T);
ac.getFail();
ac.find(T);
printf("%d\n", ac.cnt);
}
return ;
}

hdu 2222 Keywords Search(AC自动机)的更多相关文章

  1. hdu 2222 Keywords Search——AC自动机

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2222 第一道AC自动机! T了无数边后终于知道原来它是把若干询问串建一个自动机,把模式串放在上面跑:而且只 ...

  2. hdu 2222 Keywords Search ac自动机入门

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:有N(N <= 10000)个长度不超过50的模式串和一个长度不超过1e6的文本串. ...

  3. HDU 2222 Keywords Search(AC自动机模板题)

    学习AC自动机请戳这里:大神blog........ 自动机的模板: #include <iostream> #include <algorithm> #include < ...

  4. HDU 2222 Keywords Search (AC自动机)

    题意:就是求目标串中出现了几个模式串. 思路:用int型的end数组记录出现,AC自动机即可. #include<iostream> #include<cstdio> #inc ...

  5. hdu 2222 Keywords Search ac自动机模板

    题目链接 先整理一发ac自动机模板.. #include <iostream> #include <vector> #include <cstdio> #inclu ...

  6. HDU 2222 Keywords Search (AC自动机)(模板题)

    <题目链接> 题目大意: 给你一些单词,和一个字符串,问你这个字符串中含有多少个上面的单词. 解题分析: 这是多模匹配问题,如果用KMP的话,对每一个单词,都跑一遍KMP,那么当单词数量非 ...

  7. hdu 2222 Keywords Search - Aho-Corasick自动机

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submissio ...

  8. hdoj 2222 Keywords Search(AC自动机)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 思路分析:该问题为多模式匹配问题,使用AC自动机解决:需要注意的问题是如何统计该待查询的字符串包 ...

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

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

  10. HDU 2222 Keywords Search AC自己主动机入门题

    单词统计的题目,给出一些单词,统计有多少单词在一个文本中出现,最经典的入门题了. AC自己主动机的基础: 1 Trie. 以这个数据结构为基础的,只是添加一个fail指针和构造fail的函数 2 KM ...

随机推荐

  1. 微信小程序火车票查询 直取12306数据

    最终效果图: 样式丑哭了,我毕竟不是前端,宗旨就是练练手,体验微信小程序的开发,以最直接的方式获取12306数据查询火车票. 目录结构: search1是出发站列表,search2是目的站列表,命名没 ...

  2. App Framework $.ui.loadContent 参数解释

    在使用 app Framework 的 $.ui.loadContent(target,newTab,goBack,transition);时 对 newTab goback两个参数一直不得其解.通过 ...

  3. jquery-lazyload延迟加载图片

    下载地址:https://github.com/tuupola/jquery_lazyload用法:头部引用<script src="jquery.js" type=&quo ...

  4. 【hihoCoder】1121:二分图一·二分图判定

      题目   http://hihocoder.com/problemset/problem/1121 无向图上有N个点,两两之间可以有连线,共有M条连线. 如果对所有点进行涂色(白/黑),判定是否存 ...

  5. ajax 全套

    ajax简介 AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术.Ajax不是一种新的编程语言, ...

  6. markdown预览-快速入门

    最近要写文档,领导指定用markdown. 这个两三年前用过两次的神器工具,都忘的差不多了. 为了熟练一点这个技能,决定好好的重新学一次. 于是乎:看快速入门文档 ...30分钟...看完文档发现要来 ...

  7. Oracle CDC配置案例

    异步部署 1. 环境的配置准备 1.1.    数据库版本 SQL> select * from v$version; BANNER ------------------------------ ...

  8. CentOS6.5安装Eclipse

    安装说明 1.安装环境: CentOS6.5 64位系统 2.安装方式:tar.gz安装 3.软 件 包:eclipse-jee-luna-SR1-linux-gtk-x86_64.tar.gz 4. ...

  9. redis主从复制配置

    master配置 主要是下面配置 # ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the # intern ...

  10. androidannotations 简单复制与点击事件(1)

    现在最火的android开发框架 简单描述一下 这一篇简单描述寻找控件以及事件的使用 1.该方法可以不用写setconteview @EActivity(R.layout.activity_main) ...