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;
}


發佈了59 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章