AC自动机(hdu 2896 hdu 3065)

来源:互联网 发布:阿里java工资水平 编辑:程序博客网 时间:2024/05/16 19:55

题目:hdu 2896

题意:中文题目,可自己理解,简单说就是给定一些子字符串,再给出一些母字符串,找出母字符串中包含哪些子字符串

题解:AC自动机模板题

代码:

动态申请:

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<queue>#define MAX 59999using 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;}


0 0