生活随笔
收集整理的這篇文章主要介紹了
AC自动机-洛谷3121 [USACO15FEB]审查(黄金)Censoring (Gold)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
https://www.luogu.org/problem/show?pid=3121#sub
首先題目看清楚
FJ注意到列表中的單詞不會(huì)出現(xiàn)一個(gè)單詞是另一個(gè)單詞子串的情況,這意味著每個(gè)列表中的單詞在S中出現(xiàn)的開(kāi)始位置是互不相同的
這意味著你在找答案時(shí),當(dāng)一個(gè)節(jié)點(diǎn)正常訪問(wèn)的時(shí)候,你不用去尋找fail;
你只要在匹配失敗的時(shí)候取fail就好了;
關(guān)于fail的意義,可以看我AC自動(dòng)機(jī)的博客;
然后我們?cè)谠靦rie時(shí),順便把一個(gè)字符串的長(zhǎng)度記錄下來(lái);
end=一個(gè)字符串的長(zhǎng)度;
然后我們開(kāi)2個(gè)棧;
a[]記錄當(dāng)前搜到那個(gè)點(diǎn);
b[]記錄當(dāng)前搜那個(gè)char;
然后如果發(fā)現(xiàn)當(dāng)前節(jié)點(diǎn)是end;
直接彈出棧頂end個(gè)元素;
更新now指針,繼續(xù)搜;
好了;
有個(gè)事情要注意;
我原始的AC自動(dòng)機(jī);
void makezyy(){
for(
int i=
0;i<
26;i++)
if(T[
0].nxt[i])
q[++r]=T[
0].nxt[i];
while(r>l){
int x=
q[++l];
for(
int i=
0;i<
26;i++)
if(T[
x].nxt[i]){
q[++r]=T[
x].nxt[i];
int y=T[
x].fail;
while(
y&&!T[
y].nxt[i])
y=T[
y].fail;T[
q[r]].fail=T[
y].nxt[i];}}
}
void find(
int m){
int o=
0;
for(
int i=
0;i<
m;i++){
int x=
s[i]-
'a';
int y=o;
while(
y&&!T[
y].nxt[
x])
y=T[
y].fail;o=T[
y].nxt[
x];a[++tot]=o;b[tot]=i;
if(T[o].E){tot-=T[o].E;o=a[tot];} }
}
大家看,這個(gè)好理解,但是用了while循環(huán),會(huì)被卡一個(gè)點(diǎn);
那我們看看更優(yōu)的寫(xiě)法;
void makezyy(){
for(
int i=
0;i<
26;i++)
if(T[
0].nxt[i])
q[++r]=T[
0].nxt[i];
while(r>l){
int x=
q[++l];
for(
int i=
0;i<
26;i++)
if(!T[
x].nxt[i])T[
x].nxt[i]=T[T[
x].fail].nxt[i];
else{
q[++r]=T[
x].nxt[i];T[T[
x].nxt[i]].fail=T[T[
x].fail].nxt[i];}}
}
void find(
int m){
int o=
0;
for(
int i=
0;i<
m;i++){o=T[o].nxt[
s[i]-
'a'];a[++tot]=o;b[tot]=i;
if(T[o].E){tot-=T[o].E;o=a[tot];} }
}
種方法巧妙地運(yùn)用地推;
兩種方法求出的fail值是相同的;
但是這種方法會(huì)無(wú)法辨別出某個(gè)節(jié)點(diǎn)在一開(kāi)始有沒(méi)有某個(gè)兒子;
因?yàn)閙akezyy之后空的兒子自動(dòng)變成了fail;
好像還可以優(yōu)化的吧;
using namespace std;
struct trie{
int nxt[
26],fail,E;
}T[
100005];
int q[100005],l,r,a[
100005],b[
100005],tot;
int n,
m,ll;
char
s[
100005],c[
100005];
void init(
int m){
int o=
0;
for(
int i=
0;i<
m;i++){
int x=c[i]-
'a';
if(!T[o].nxt[
x])T[o].nxt[
x]=++ll;o=T[o].nxt[
x];}T[o].E=
m;
}
void makezyy(){
for(
int i=
0;i<
26;i++)
if(T[
0].nxt[i])
q[++r]=T[
0].nxt[i];
while(r>l){
int x=
q[++l];
for(
int i=
0;i<
26;i++)
if(!T[
x].nxt[i])T[
x].nxt[i]=T[T[
x].fail].nxt[i];
else{
q[++r]=T[
x].nxt[i];T[T[
x].nxt[i]].fail=T[T[
x].fail].nxt[i];}}
}
void find(
int m){
int o=
0;
for(
int i=
0;i<
m;i++){o=T[o].nxt[
s[i]-
'a'];a[++tot]=o;b[tot]=i;
if(T[o].E){tot-=T[o].E;o=a[tot];} }
}
int main()
{scanf(
"%s",
s);scanf(
"%d",&n);
while(n--)scanf(
"%s",c),init(strlen(c));makezyy();find(strlen(
s));
for(
int i=
1;i<=tot;i++)cout<<
s[b[i]];
}
轉(zhuǎn)載于:https://www.cnblogs.com/largecube233/p/6797890.html
總結(jié)
以上是生活随笔為你收集整理的AC自动机-洛谷3121 [USACO15FEB]审查(黄金)Censoring (Gold)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。