這道題的話用到了dp,乙個比較簡單的dp方程
poj3691我第一眼看到這道題的時候,一度懷疑是模板題,然後定睛一看,沒這麼簡單,應該我們在修改的時候要盡可能的找位置去修改更多的字元,所以這就意味這我們可能要用到最方便的繼承狀態的dp(當然作為乙個dp盲人,我一開始是沒有想到的,只有暴力才是王道),下面看一下講解時間限制: 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
說難的話就不能說特別難,只是有一些細節要弄清楚,然後一切問題都游刃而解,剩下的就看**的實現吧
(注釋版,我已經把細節講清楚了,所以的話可以嘗試自己挑戰一下,然後再poj提交)
1 #include2 #include3 #include4 #include5 #include6 #include7tristan code 注釋版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 }
(非注釋版,最好就按照這個學習啦)
1 #include2 #include3 #include4 #include5 #include6 #include7tristan code 非注釋版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 }
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.多模式串...