綠掉的代碼
敲簡單的,康康代碼吧!
#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站看多了[複雜])