hdoj 2222 Keywords Search 【字典树挤进1ms----啊--我要学AC自动机】
2016-08-11 09:34
369 查看
传送门:2222
正要学AC自动机--发现 k*n=5*10^7 -- 就用单纯的字典树过了--
建树--扫描字符串--统计---
代码:
—————————————————————————————————————————————————————————————————————————————
AC机中主要的是fail指针的创建,这里采用bfs来一层一层的创建,每个结点的fail所指的层数当然小于它自身的层数呀,
然后第一层的都指向root,
剩下的举个例子
ABCDE 加入D的fail指向了 CD的D,那么我们求E的fail时,就是找一个D的fail 或 fail...的fail..... ,第一个后面有E的,那个E就是 ABCDE的E的fail所指的。
AC机代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
long long ans ;
char ch[60];
char str[10001000];
struct node{
node * next[26];
node * fail;
int sum;
bool falg;
node():sum(0),falg(false),fail(NULL){
memset(next,0LL,sizeof(next));
}
};
node * root;
void build(){
int ll = strlen(ch),x;
node * p = root;
for (int i=0;i<ll;i++){
x = ch[i]-'a';
if (p->next[x]==NULL) p->next[x] = new node();
p = p->next[x];
}
p->sum++;
// printf("%s %d %d\n",ch,p->sum,p);
}
void dele(node * root){
for (int i=0;i<26;i++){
if (root->next[i]!=NULL){
dele(root->next[i]);
}
}
delete root;
}
void getfail(){
root->fail = root;
queue<node *> que;
que.push(root);
int ca = 2;
while (!que.empty()){
node * temp = que.front();
que.pop();
for (int i=0;i<26;i++){
if (temp->next[i]!=NULL){
node * p = temp;
que.push(p->next[i]);
while (p!=root){
if (p->fail->next[i]!=NULL){
temp->next[i]->fail = p->fail->next[i];
break;
}else{
p = p->fail;
}
}
if (p==root){
temp->next[i]->fail = root;
}
// temp->next[i]->sum += (temp->next[i]->fail->sum);
}
}
}
}
void sumToZero(node * p){
while (!p->falg){
ans += p->sum;
p->falg = true;
p = p->fail;
}
}
void AC(){
node * p = root;
int ll = strlen(str),x;
for (int i=0;i<ll;i++){
x = str[i] - 'a';
if (p->next[x]!=NULL){
p = p->next[x];
}else{
while (p!=root){
p = p->fail;
if (p->next[x]!=NULL){
p=p->next[x];
break;
}
}
}
// if (p->sum!=0){
// ans += p->sum;
sumToZero(p);
// printf("%c %d ---\n",str[i],ans);
// }
}
}
void slove(){
int n;scanf("%d",&n);
root = new node();
root->falg = true;
for (int i=0;i<n;i++){
scanf("%s",ch);
build();
}
getfail();
scanf("%s",str);
ans = 0;
AC();
printf("%lld\n",ans);
dele(root);
}
int main()
{
int T;scanf("%d",&T);
while (T--){
slove();
}
return 0;
}
正要学AC自动机--发现 k*n=5*10^7 -- 就用单纯的字典树过了--
建树--扫描字符串--统计---
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct trie{ trie * child[26]; int shu; int hao; }P[600000]; int ii=0,kp,op[10100]; trie * boot = & P[0]; void create(char xx[],int ii)//建树 { trie * k=boot; int j,ll=strlen(xx); for (int i=0;i<ll;i++) { j=xx[i]-'a'; if (!k->child[j]) { P[kp].hao=kp; P[kp].shu=0; k->child[j]=&P[kp++]; } k=k->child[j]; } op[ii]=k->hao; } void sou(char xx[])//匹配 { trie * k=boot; int j; for (int i=0;xx[i];i++) { j=xx[i]-'a'; if (!k->child[j]) return; k=k->child[j]; k->shu++; } } void sol() { int n;scanf("%d",&n); char ch[60];kp=1; memset(P,0,sizeof(P)); for (int i=1;i<=n;i++) { scanf("%s",ch); create(ch,i); } char opop[1000100]; scanf("%s",opop); int ll=strlen(opop); for (int i=0;i<ll;i++) sou(opop+i); int s=0; for (int i=1;i<=n;i++)//统计 if (P[op[i]].shu) s++; printf("%d\n",s); } int main() { int t;scanf("%d",&t); while (t--) sol(); return 0; }
—————————————————————————————————————————————————————————————————————————————
AC机中主要的是fail指针的创建,这里采用bfs来一层一层的创建,每个结点的fail所指的层数当然小于它自身的层数呀,
然后第一层的都指向root,
剩下的举个例子
ABCDE 加入D的fail指向了 CD的D,那么我们求E的fail时,就是找一个D的fail 或 fail...的fail..... ,第一个后面有E的,那个E就是 ABCDE的E的fail所指的。
AC机代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
long long ans ;
char ch[60];
char str[10001000];
struct node{
node * next[26];
node * fail;
int sum;
bool falg;
node():sum(0),falg(false),fail(NULL){
memset(next,0LL,sizeof(next));
}
};
node * root;
void build(){
int ll = strlen(ch),x;
node * p = root;
for (int i=0;i<ll;i++){
x = ch[i]-'a';
if (p->next[x]==NULL) p->next[x] = new node();
p = p->next[x];
}
p->sum++;
// printf("%s %d %d\n",ch,p->sum,p);
}
void dele(node * root){
for (int i=0;i<26;i++){
if (root->next[i]!=NULL){
dele(root->next[i]);
}
}
delete root;
}
void getfail(){
root->fail = root;
queue<node *> que;
que.push(root);
int ca = 2;
while (!que.empty()){
node * temp = que.front();
que.pop();
for (int i=0;i<26;i++){
if (temp->next[i]!=NULL){
node * p = temp;
que.push(p->next[i]);
while (p!=root){
if (p->fail->next[i]!=NULL){
temp->next[i]->fail = p->fail->next[i];
break;
}else{
p = p->fail;
}
}
if (p==root){
temp->next[i]->fail = root;
}
// temp->next[i]->sum += (temp->next[i]->fail->sum);
}
}
}
}
void sumToZero(node * p){
while (!p->falg){
ans += p->sum;
p->falg = true;
p = p->fail;
}
}
void AC(){
node * p = root;
int ll = strlen(str),x;
for (int i=0;i<ll;i++){
x = str[i] - 'a';
if (p->next[x]!=NULL){
p = p->next[x];
}else{
while (p!=root){
p = p->fail;
if (p->next[x]!=NULL){
p=p->next[x];
break;
}
}
}
// if (p->sum!=0){
// ans += p->sum;
sumToZero(p);
// printf("%c %d ---\n",str[i],ans);
// }
}
}
void slove(){
int n;scanf("%d",&n);
root = new node();
root->falg = true;
for (int i=0;i<n;i++){
scanf("%s",ch);
build();
}
getfail();
scanf("%s",str);
ans = 0;
AC();
printf("%lld\n",ans);
dele(root);
}
int main()
{
int T;scanf("%d",&T);
while (T--){
slove();
}
return 0;
}
相关文章推荐
- HDOJ 2222 - Keywords Search 更新AC自动机模板...用类来表示
- HDU 2222 Keywords Search【AC自动机|字典树】
- HDOJ 2222 Keywords Search(AC自动机入门)
- HDOJ-2222 Keywords Search 字典树+AC自动机(三叉树实现字典树)
- hdoj 2222 Keywords Search 【AC自动机 入门题】 【求目标串中出现了几个模式串】
- HDOJ2222Keywords Search【AC自动机模板题】
- HDU 2222 Keywords Search(AC自动机模板)
- hdu 2222 Keywords Search(字典树)
- 【AC自动机】HDU 2222 Keywords Search
- 【AC自动机】HDU 2222 Keywords Search 裸题
- hdu 2222 Keywords Search(AC自动机入门)
- 文章标题 HDU 2222 : Keywords Search (AC自动机模板)
- hdu 2222 Keywords Search(AC自动机)
- Match:Keywords Search(AC自动机模板)(HDU 2222)
- [HDU 2222] Keywords Search [AC自动机]
- HDU 2222 Keywords Search (AC自动机 经典)
- HDU 2222 Keywords Search【AC自动机】
- HDU 2222 Keywords Search 【AC自动机模板】
- HDU--2222--Keywords Search--AC自动机
- HDU 2222 Keywords Search 【AC自动机(模板题)】