題目:hdu 2896
題意:中文題目,可自己理解,簡單說就是給定一些子字符串,再給出一些母字符串,找出母字符串中包含哪些子字符串
題解:AC自動機模板題
代碼:
動態申請:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#define MAX 59999
using namespace std;
struct Node
{
int number;
Node *next[128];
Node *fail;
Node()
{
number=0;
fail=NULL;
for(int i=0;i<128;i++)
next[i]=NULL;
}
};
queue<Node*> q;
Node *root;
bool vis[600];
int no;
char son[256];
char father[100500];
void insertTree(char *s)
{
int len=strlen(s);
int index;
Node *temp=root;
for(int i=0;i<len;i++)
{
index=s[i]-' ';
if(temp->next[index]==NULL)
{
temp->next[index]=new Node();
}
temp=temp->next[index];
}
temp->number=no++;
}
void buildacfail()
{
q.push(root);
Node *temp;
Node *p;
while(!q.empty())
{
temp=q.front();
q.pop();
for(int i=0;i<128;i++)
{
if(temp->next[i]!=NULL)
{
if(temp==root)
{
temp->next[i]->fail=root;
}
else
{
p=temp->fail;
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
temp->next[i]->fail=p->next[i];break;
}
p=p->fail;
}
if(p==NULL)
{
temp->next[i]->fail=root;
}
}
q.push(temp->next[i]);
}
}
}
}
int query(char *s)
{
int len=strlen(s);
Node *temp=root;
Node *p;
int index;
int sum=0;
for(int i=0;i<len;i++)
{
index=s[i]-' ';
while(temp->next[index]==NULL && temp!=root)
{
temp=temp->fail;
}
temp=temp->next[index];
if(temp==NULL)
{
temp=root;
}
p=temp;
while(temp!=root && !vis[temp->number])
{
if(temp->number)
{
sum++;vis[temp->number]=1;
}
temp=temp->fail;
}
temp=p;
}
return sum;
}
int main()
{
int n,m,sum;
while(~scanf("%d", &n))
{
root =new Node();
no=1;
getchar();
for(int i = 0; i < n; ++i)
{
gets(son);
insertTree(son);
}
buildacfail();
scanf("%d",&m);
getchar();
memset(vis,0,sizeof(vis));
sum=0;
for(int i=0;i<m;i++)
{
scanf("%s", father);
int count1=query(father);
if(count1)
{
sum++;
printf("web %d:",i+1);
for(int j=1;j<=n;j++)
{
if(vis[j]){printf(" %d",j);vis[j]=0;count1--;}
if(!count1) break;
}
printf("\n");
}
}
printf("total: %d\n",sum);
}
return 0;
}
靜態存儲:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
struct Node
{
int number;
Node *next[128];
Node *fail;
};
queue<Node*> q;
Node *root;
Node node[1000050];
int num;
int no;
bool vis[505];
char son[300];
char father[10050];
void declear(Node *p)
{
p->number=0;
p->fail=NULL;
for(int i=0;i<128;i++)
{
p->next[i]=NULL;
}
}
void insertTree(char *s)
{
int len=strlen(s);
int index;
Node *temp=root;
for(int i=0;i<len;i++)
{
index=s[i]-' ';
if(temp->next[index]==NULL)
{
temp->next[index]=&node[num];
declear(node+num);
num++;
}
temp=temp->next[index];
}
temp->number=no++;
}
void buildacfail()
{
q.push(root);
Node *temp;
Node *p;
while(!q.empty())
{
temp=q.front();
q.pop();
for(int i=0;i<128;i++)
{
if(temp->next[i]!=NULL)
{
if(temp==root)
{
temp->next[i]->fail=root;
}
else
{
p=temp->fail;
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
temp->next[i]->fail=p->next[i];break;
}
p=p->fail;
}
if(p==NULL)
{
temp->next[i]->fail=root;
}
}
q.push(temp->next[i]);
}
}
}
}
int query(char *s)
{
int len=strlen(s);
Node *temp=root;
Node *p;
int index;
int sum=0;
for(int i=0;i<len;i++)
{
index=s[i]-' ';
while(temp->next[index]==NULL && temp!=root)
{
temp=temp->fail;
}
temp=temp->next[index];
if(temp==NULL)
{
temp=root;
}
p=temp;
while(temp!=root && !vis[temp->number]) //考慮重複情況,不用記錄次數,只要記錄之前有沒出現過即可,後面的就不用考慮了
{
if(temp->number!=0)
{
sum++;
vis[temp->number]=1;
}
temp=temp->fail;
}
temp=p;
}
return sum;
}
int main()
{
int n,m,sum;
while(~scanf("%d", &n))
{
root = node;
num=1;
no=1;
declear(node);
getchar();
for(int i = 0; i < n; ++i)
{
gets(son);
insertTree(son);
}
buildacfail();
scanf("%d",&m);
getchar();
memset(vis,0,sizeof(vis));
sum=0;
for(int i=0;i<m;i++)
{
scanf("%s", father);
int count1=query(father);
if(count1)
{
sum++;
printf("web %d:",i+1);
for(int j=1;j<=n;j++)
{
if(vis[j]){printf(" %d",j);vis[j]=0;count1--;}
if(!count1) break;
}
printf("\n");
}
}
printf("total: %d\n",sum);
}
return 0;
}
題目:hdu 3065
題意:中文題目,簡單說就是給定一些大寫字母組成的子串,再給出母串,求其母串中子串各出現了多少次
題解:AC模板題,主要解釋看註釋
代碼:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
struct Node
{
int number;
Node *next[26];
Node *fail;
};
queue<Node*> q;
Node *root;
Node node[5000050];
int num;
int no;
int vis[1505];
char son[1005][60];
char father[2000500];
void declear(Node *p)
{
p->number=0;
p->fail=NULL;
for(int i=0;i<26;i++)
{
p->next[i]=NULL;
}
}
void insertTree(char *s)
{
int len=strlen(s);
int index;
Node *temp=root;
for(int i=0;i<len;i++)
{
index=s[i]-'A';
if(temp->next[index]==NULL) //增加節點
{
temp->next[index]=&node[num];
declear(node+num);
num++;
}
temp=temp->next[index];
}
temp->number=no++;
}
void buildacfail()
{
q.push(root);
Node *temp;
Node *p;
while(!q.empty())
{
temp=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(temp->next[i]!=NULL)
{
if(temp==root)
{
temp->next[i]->fail=root;
}
else
{
p=temp->fail;
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
temp->next[i]->fail=p->next[i];break;
}
p=p->fail;
}
if(p==NULL)
{
temp->next[i]->fail=root;
}
}
q.push(temp->next[i]);
}
}
}
}
void query(char *s)
{
int len=strlen(s);
Node *temp=root;
Node *p;
int index;
for(int i=0;i<len;i++)
{
index=s[i]-'A';
if(index>=26 ||index<0 ) {temp=root;continue;}
while(temp->next[index]==NULL && temp!=root)
{
temp=temp->fail;
}
temp=temp->next[index];
if(temp==NULL)
{
temp=root;
}
p=temp;
while(temp!=root) //全部進行遍歷,而不是,這道題改的就是這裏,不是重新開始,而是順着現在的遍歷,一定不會重複
{
if(temp->number!=0)
{
vis[temp->number]++;
}
temp=temp->fail;
}
temp=p;
}
}
int main()
{
int n,m,sum;
while(~scanf("%d", &n))
{
memset(vis,0,sizeof(vis));
root = node;
num=1;
no=1;
declear(node);
getchar();
for(int i = 0; i < n; ++i)
{
gets(son[i]);
insertTree(son[i]);
}
buildacfail();
scanf("%s", father);
query(father);
for(int i=1;i<=n;i++)
{
if(vis[i]) printf("%s: %d\n",son[i-1],vis[i]);
}
}
return 0;
}