AC自动机(hdu 2896 hdu 3065)

题目: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值