洛谷 - P2444 - 病毒 - AC自动机

https://www.luogu.org/problemnew/show/P2444

有点恶心,不太明白fail的意义。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

struct Trie{
    int nex[60010][2],fail[60010],End[60010];
    int root,L;
    int newnode(){
        /*for(int i=0;i<26;i++)
            nex[L][i]=-1;*/
        End[L++]=0;
        return L-1;
    }

    int cnt;
    void init(){
        L=0;
        cnt=0;
        memset(nex,-1,sizeof(nex));
        root=newnode();
    }

    void insert(char buf[]){
        int len=strlen(buf);
        int now=root;
        for(int i=0;i<len;i++){
            int &t=nex[now][buf[i]-'0'];
            if(t==-1)
                t=newnode();
            now=t;
        }
        End[now]++;
        cnt++;
    }

    void build(){
        queue<int>Q;
        fail[root]=root;
        for(int i=0;i<2;i++){
            if(nex[root][i]==-1){
                nex[root][i]=root;
                //根节点没有对应的分支,还是必须回到根节点开始匹配
            }
            else{
                //根节点的后继失配,先假定回到根节点匹配
                fail[nex[root][i]]=root;
                Q.push(nex[root][i]);
            }
        }
        while(!Q.empty()){
            int now=Q.front();
            Q.pop();
            for(int i=0;i<2;i++)
                if(nex[now][i]==-1){
                    //某个节点没有这个对应的分支,它失配了,沿着失配边去到最近的有这个分支的边?
                    nex[now][i]=nex[fail[now]][i];
                }
                else{
                    fail[nex[now][i]]=nex[fail[now]][i];
                    Q.push(nex[now][i]);
                    //如果这个节点的fail指针指向的点是End,那么因为这个节点蕴含他的fail节点,所以他也是End
                    End[now]|=End[fail[now]];
                }
        }
    }


    /*int query(char buf[]){
        int len=strlen(buf);
        int now=root;
        int res=0;
        for(int i=0;i<len;i++){
            now=nex[now][buf[i]-'0'];
            int temp=now;
            while(temp!=root&&End[temp]!=-1){
                res+=End[temp];
                End[temp]=-1;
                temp=fail[temp];
            }
            //if(res==cnt)
                //return res;
        }
        return res;
    }*/

    int vis[60005];
    int instack[60005];
    int find_circle(){
        memset(vis,0,sizeof(vis));
        memset(vis,0,sizeof(instack));
        return dfs(root);
    }

    int dfs(int id){
        instack[id]=1;
        vis[id]=1;
        for(int i=0;i<2;i++){
            if(instack[nex[id][i]]){
                //该节点的下一条边在dfs栈中,是反向边
                printf("TAK\n");
                exit(0);
            }
            if(vis[nex[id][i]]==0){
                //不访问已经到过的表亲,表亲不可能成环
                if(End[nex[id][i]]==0){
                    //下一个点不是病毒
                    dfs(nex[id][i]);
                }
            }
        }
        instack[id]=0;
        return 0;
    }


};

char buf[100010];

Trie ac;

int n;
void solve(){
    while(~scanf("%d",&n)){
        if(n==0)
            break;
        ac.init();

        for(int i=0;i<n;i++){
            scanf("%s",buf);
            ac.insert(buf);
        }
        ac.build();
        //scanf("%s",buf);

        if(ac.find_circle()==0){
            cout<<"NIE"<<endl;
        }
    }
}

int main(){
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    solve();
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/10538026.html