自動AC機是如何運行的

在這裏插入圖片描述

今天你AC了嗎,快來康康自動AC,來解決你每天的煩惱吧~

綠掉的代碼

敲簡單的,康康代碼吧!

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct Trie_Tree{
    ll fail;
    ll child[27];//每父節點下的子節點有26個(26個字母)※child[]表示當前訪問的節點 
    ll end;//標記有幾個單詞以這個節點結尾
}ac[1000000 + 10];
ll cnt = 0;//Trie的指針
inline void Build(string mushichuan){//建樹 
    ll l = mushichuan.length();
    ll now = 0;//訪問字典樹的當前位置 
    for(ll i = 0; i < l; i++){//構造Trie樹
        if(ac[now].child[mushichuan[i] - 'a'] == 0)//樹沒這個節點, s[i] - 'a' 把對應的字母變成數字 
            ac[now].child[mushichuan[i] - 'a'] = ++cnt;//如 "A B C" 需要構造三層,每一層都事先把 a~z 26個字母打好 
            now = ac[now].child[mushichuan[i] - 'a'];//往下遞歸
    }//最後跳出循環需把單詞結尾標記一下 
    ac[now].end++;
}
void get_fail(){//構造fail指針
    queue <ll> q;
    for(ll i = 0; i <= 26; i++){//初始條件 
        if(ac[0].child[i] != 0){//構造了此節點, ac[0] 表示根節點 
            ac[ac[0].child[i]].fail = 0;//先把所有的第二層節點都指向根節點
            q.push(ac[0].child[i]);//把根節點的子節點 push 進 queue 中     
        }
    }
    while(!q.empty()){//bfs求每一相同的字符串,再將fail指針指向相同字符串的子節點 
        ll father = q.front();
        q.pop();
        for(ll i = 0; i < 26; i++){
            if(ac[father].child[i] != 0){//父節點下存在子節點
                ac[ac[father].child[i]].fail = ac[ac[father].fail].child[i];//看圖解
                q.push(ac[father].child[i]);//像第一層把父節點的子節點 push 進 queue 中
            }
            else//父節點下不存在子節點
                ac[father].child[i] = ac[ac[father].fail].child[i];//虛根(看圖解) 
        }
    }
}
ll AC_COUT(string wenbenchuan){//自動AC機的匹配
    ll l = wenbenchuan.length();
    ll now = 0, ans = 0;//now = 0 先從根結點出發 
    for(ll i = 0; i< l; i++){
        now = ac[now].child[wenbenchuan[i] - 'a'];//向下走, s[i] - 'a' 把對應的字母變成數字 
        for(ll next = now; next && ac[next].end != -1; next = ac[next].fail){//下一個節點沒有 || 沒有訪問過, 循環求解
            ans += ac[next].end;//計算單詞節點(看圖解) 
            ac[next].end = -1;//與上方對應,就不會重複使用 
        }
    }
    return ans; 
}
int main(){
    ll n;
    string mushichuan, wenbenchuan;
    cin >> n;
    for(ll i = 1; i <= n; i++){
        cin >> mushichuan;
        Build(mushichuan);//建樹
    }
    ac[0].fail = 0;//根節點的 fail 指針指向 0(結束標誌)
    get_fail();//構造fail指針
    cin >> wenbenchuan;
    cout << AC_COUT(wenbenchuan) << endl;
    return 0;
}

希望大家多多提出寶貴的意見!

既然你耐心看完了這篇題解,何不如一鍵三連再走呢?Thanks♪(・ω・)ノ (B站看多了[複雜])

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章