AC自動機練習2 修改串

2021-09-26 07:10:30 字數 3879 閱讀 2238

這道題的話用到了dp,乙個比較簡單的dp方程

poj3691

時間限制: 1 sec  記憶體限制: 128 mb

提交: 18  解決: 14

[提交] [狀態] [討論版] [命題人:admin]

題目描述

【題意】

給出n個模式串,然後給出乙個修改串,求盡量少修改修改串,使得修改串不含有任何乙個模式串,不能的話輸出-1

每個串只有'a','c','g','t'四個字母

【輸入格式】

有多組資料,輸入以乙個0結束

每組資料:

輸入乙個n(n<=50)

接下來n行輸入n個模式串(每個模式串長度不超過20)

最後一行輸入修改串(長度不超過1000)

【輸出格式】

輸出case t: ans

t當前輸出的是第t組資料,ans表示最少修改次數,不能修改則ans=-1

【樣例輸入】

2aaa

aagaaag    2a

tgtgaatg4a

gctagt

0【樣例輸出】

case 1: 1

case 2: 4

case 3: -1

我第一眼看到這道題的時候,一度懷疑是模板題,然後定睛一看,沒這麼簡單,應該我們在修改的時候要盡可能的找位置去修改更多的字元,所以這就意味這我們可能要用到最方便的繼承狀態的dp(當然作為乙個dp盲人,我一開始是沒有想到的,只有暴力才是王道),下面看一下講解

說難的話就不能說特別難,只是有一些細節要弄清楚,

然後一切問題都游刃而解,剩下的就看**的實現吧

(注釋版,我已經把細節講清楚了,所以的話可以嘗試自己挑戰一下,然後再poj提交)

1 #include2 #include3 #include4 #include5 #include6 #include7

using

namespace

std;

8struct

node

9tr[2010

];14

int tot,list[2010

];15

char a[2010

];16

void clean(int x)/*

多組資料清空樹

*/17

22int id(char c)/*

為了方便,我們把要處理的數字都直接轉化成數字

*/23

29void build_tree()/*

建樹板子

*/30

40 x=tr[x].cnt[y];41}

42 tr[x].s++;43}

44void bfs()/*

構造失敗指標

*/45

59if(x==0) tr[son].fail=0;/*

根節點的fail值為0

*/60

else

6173 j=tr[j].fail;/*

繼續繼承

*/74}75

if(j==-1) tr[son].fail=0;/*

如果這個點不存在,那麼x兒子的失敗指標就指向根節點

*/76

}77 list[++tail]=son;78}

79 head++;80}

81}82int f[2100][2100

],p,n,ans;

83/*

f陣列是用來執行dp的,p是輸入的模式串的個數,n是修改串的長度,ans記錄答案

84f[i][j]表示當前在第i位(修改串),匹配到ac自動機上(字典樹)的第j個結點,

85轉移時,考慮新增乙個字元,在ac自動機上獲取新增這個結點會轉移到的下乙個結點(字串匹配),並判斷這樣轉移是否形成了乙個模式串。

86讀到i個字元時,對應於j狀態(dp的過程要兩重迴圈i和j),要轉移到son[j](j的子節點狀態,在這裡用k在[1,4]一重迴圈遍歷所有可以轉字元),

87如果第i個字元跟所要轉移到的字元相同,則代價為0,因為不需要改變;否則代價為1,因為需要改變

*/88

void

dp()

89103

}104

}105 ans=999999999

;106

for(int i=0;i<=tot;i++) ans=min(ans,f[n][i]);

107if(ans==999999999) ans=-1;/*

一遍一遍更新答案

*/108

}109

intmain()

110119 scanf("

%s",a+1); n=strlen(a+1);/*

長度*/

120 bfs(); dp();/*

失敗標記跑一邊,然後dp跑一邊找答案

*/121 printf("

case %d: %d\n

",t,ans);

122}

123return0;

124 }

tristan code 注釋版

(非注釋版,最好就按照這個學習啦)

1 #include2 #include3 #include4 #include5 #include6 #include7

using

namespace

std;

8struct

node

9tr[2010

];12

int tot,list[2010

];13

char a[2010

];14

void clean(int

x)15

19int id(char

c)20

26void

build_tree()

2737 x=tr[x].cnt[y];38}

39 tr[x].s++;40}

41void

bfs()

4257

if(x==0) tr[son].fail=0;58

else

5970 j=tr[j].fail;71}

72if(j==-1) tr[son].fail=0;73

}74 list[++tail]=son;75}

76 head++;77}

78}79int f[2100][2100

],p,n,ans;

80void

dp()

8194}95

}96 ans=999999999;97

for(int i=0;i<=tot;i++) ans=min(ans,f[n][i]);

98if(ans==999999999) ans=-1;99

}100

intmain()

101110 scanf("

%s",a+1); n=strlen(a+1

);111

bfs(); dp();

112 printf("

case %d: %d\n

",t,ans);

113}

114return0;

115 }

tristan code 非注釋版

AC自動機 建立nlogn個AC自動機

string set queries 題意 給你3種操作,1 加入乙個串到集合中。2 刪除集合中的某乙個串 3 查詢集合中的字串在給定的字串種出現幾次。同乙個串可重複 解法 建立多個ac自動機,用二進位制分組來處理。加入給你21個串 分為 16 4 1,再新增乙個串的時候,即21 1,22 16 4...

AC自動機及字尾自動機

ac自動機是一種基於trie樹的演算法,其本質和kmp上的處理很相似。trie樹結構 kmp轉移思路 ac自動機組要由三個部分組成 trie樹的建立 fail指標的匹配 對ac自動機的詢問 每次建立自動機會有一次初始化 ac自動機類 struct node node結構體 struct ac voi...

字串 2 AC自動機

ac自動機,其實就是trie樹與kmp的結合,且有dfa 有限狀態機 的性質.理解的關鍵點 1.fail指標 起到回溯作用 2.每次匹配都是主串不動,移動指標now去回溯找字尾的字首 3.乙個優化點,將null指向root 編碼更簡單.考察時一般也會問道dfa的性質.ac自動機解決問題 1.多模式串...