作為一道蹂躪了我一天的題…我也沒啥好說的了qaq…
思路概述
我們知道,ac自動機是一種多模字串匹配演算法。構造 trie 樹 後,在模式串末尾一位的結點作上標記。平常的 ac自動機 是盡量能多接觸到這些標記,使總值最大。本題倒是有點奇葩,要構造乙個可行的無限長文字串,使沒有任何子串為給出模式串中的乙個。也就是說,我們需要讓平常 ac自動機 的查詢操作,盡量避免標記,能用失配指標跳轉就跳轉。
因為要有無限長的可行串,根據 ac自動機 的原理,我們可以將結點連線到兒子的邊當作一條單向邊,同時失配指標也當作一條單向邊,如果存在乙個環,且環上沒有任何危險標記(即病毒**段末尾一位的結點專門作的編號),此時 ac自動機 能一直在環上匹配,並且永遠也不會得到為模式串的乙個子串,就像程式中的死迴圈一樣。這個找環我們可以通過 dfs 來實現。
注意事項
1 . 我們需要建立兩個布林陣列,其中乙個布林陣列記錄每個節點在當前 dfs 走的路徑上有沒有被選中,另乙個布林陣列記錄每個節點歷史上有沒有被訪問過。如果當前路徑形成迴路,就找到環了,應該還是比較好實現的。
2 . 避免危險標記,也就是說如果下乙個結點擁有危險標記,就不走那個結點。
3 . 在構造失配指標時,乙個很明顯的優化是:如果乙個結點擁有了失配指標,它指向的結點如果有危險標記,自己必然也危險,因為它到根結點形成的串是自己到根節點的字尾。
4.為什麼要兩個bool標記?因為如圖1,如果不能保證當前dfs時在sta中的節點是鏈式結構的話,就會可能出現誤判為環的可能。
5.為什麼要在造指標的時候做優化,除了時間上的考慮似乎還有別的因素…如圖吧。否則的話,如果只訪問子節點,那永遠成不了環。訪問fail節點的話,又可能自環。
}else temp->next1[i]=temp->fail->next1[i];//優化,如果沒有下乙個節點,那麼該節點就指向失配指標的對應節點
//不過這個優化放在有ac_automation函式的題目中似乎會re,具體原因暫時不明}}
}void dfs(node*p)
if(p->next1[0])
if(!p->next1[0]->tag&&!p->next1[0]->vis)
dfs(p->next1[0]);
}if(p->next1[1])
if(!p->next1[1]->tag&&!p->next1[1]->vis)
dfs(p->next1[1]);
}p->insta=false;
}int main()
build_fail_pointer();
dfs(root);
cout
<
0;}
Luogu2444 病毒(AC自動機)
洛谷 如果存在乙個無限長的串 證明可以在ac 自動機上找到乙個環 然後在上面可以無限跳 所以構建ac 自動機 在上面跑df s 就好啦 include include include include include include include include include include us...
Luogu2444 病毒(AC自動機)
洛谷 如果存在乙個無限長的串 證明可以在 ac 自動機上找到乙個環 然後在上面可以無限跳 所以構建 ac 自動機 在上面跑 dfs 就好啦 include include include include include include include include include includeu...
AC自動機 洛谷P3808 AC自動機(簡單版)
給定 n n 個模式串和1個文字串,求有多少個模式串在文字串裡出現過 多模匹配用ac role presentation aca c自動機 首先建造一棵字典樹,新增所有模式串,然後建造失配指標,最後進行匹配 luogu judger enable o2 include include include...