hods2896(AC自動機)

AC自動機:












關鍵點是字符失敗指針爲父親節點的失敗指針的兒子字母是否和該字符相同,不相同再找失敗指針的失敗指針的兒子,這樣保證了這兩個相同字符之前的字符,也就是父親字符要不沒有要不相同,代碼我加了註釋好懂一點


思路:前面的操作跟常規的AC自動機一樣,只是我們需要在結構體里加入一些額外的保存信息,比如當前字符串的編號,是否被遍歷過等等

因爲後面需要跟多個串進行比較,所以不能直接把權值賦爲-1,所以我們多加一個標記,每次標記爲i即可(每一次進入新的字符串,i都會加一,但是在當前的字符串,i標記了後就不能再進去了)


#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <queue>

using namespacestd;

#define N 300

#define M 10050

char s[N],str[M];

int a[M],t;

struct Node

{

    structNode *next[128];

    structNode *fail;

    int num,flag;

    void init()

    {

        for(int i=0; i<128; i++)

            next[i]=NULL;

        fail=NULL;

        num=0;

        flag=0;

    }

}*root;

void Insert(int id)//構造樹

{

    Node *p=root;

    int len=strlen(s);

    for(int i=0; i<len; i++)

    {

        int pos=s[i];

        if(p->next[pos]==NULL)

        {

            p->next[pos]=newNode;

            p->next[pos]->init();

        }

        p=p->next[pos];

    }

    p->num=id;//結點值爲該單詞的序號

}

void getfail()

{

    Node *p=root,*now,*son;

    queue<Node *>que;

    que.push(p);

    while(!que.empty())

    {

        now=que.front();

        que.pop();

        for(int i=0; i<128; i++)

        {

            son=now->next[i];

            if(son!=NULL)

            {

                if(now==root)

                    son->fail=root;//第一層

                else

                {

                    p=now->fail;//pnow的前綴鏈接

                    while(p)//如果到root退出,不明白爲什麼root爲空

                    {

                        if(p->next[i])//p的兒子有和son相同的字符

                        {

                            son->fail=p->next[i];//確定son的前綴鏈接

                            break;

                        }

                        p=p->fail;//找鏈接的鏈接直到root

                    }

                    if(!p)//proot

                        son->fail=root;

                }

                que.push(son);

            }

        }

    }

}

void query(int id)

{

    Node *p=root,*temp;

    int len=strlen(str);

    for(int i=0; i<len; i++)

    {

        int pos=str[i];

        while(!p->next[pos]&&p!=root)//p->next已沒值,查找pfail

            p=p->fail;

        p=p->next[pos];

        if(!p)

            p=root;//感覺有點雞肋

        temp=p;

        while(temp!=root)

        {

            if(t>=3)

                break;

            if(temp->num>0&&temp->flag!=id)//到達一個結點

            {

                a[t++]=temp->num;

                temp->flag=id;

            }

            else

                break;

            temp=temp->fail;//這一句不太懂

        }

        if(t>=3)break;

    }

}

int main()

{

    int n,m;

    while(~scanf("%d",&n))

    {

        root=newNode;

        root->init();

        getchar();

        for(int i=1; i<=n; i++)

        {

            gets(s);

            Insert(i);

        }

        getfail();

        scanf("%d",&m);

        int ans=0;

        getchar();

        for(int k=1; k<=m; k++)

        {

            t=0;

            gets(str);

            query(k);

            if(t>0)

            {

                ans++;

                sort(a,a+t);

                printf("web %d: ",k);

                for(int i=0; i<t-1; i++)

                    printf("%d ",a[i]);

                printf("%d\n",a[t-1]);

            }

        }

        printf("total: %d\n",ans);

    }

    return0;

}