1. 程式人生 > >[學習筆記]搜索——模擬與dp的結合

[學習筆記]搜索——模擬與dp的結合

狀壓dp 最短路 回溯 位置 問題: tro 新的 目的 itl

搜索:

一種基礎的算法。

考察常見於NOIP

但是高級的搜索算法可能還會在省選出現。

50%以上的暴力都可以用搜索直接枚舉來寫。

但是,當數據規模不是很大的時候,搜索也可能成為正解。

(比如剪枝PK狀壓dp)

在搜索的基礎上,可以衍生出最短路,而dp本質上,也是搜索的剪枝。

一、基礎搜索算法

DFS:

最基本的搜索。用遞歸實現。

顧名思義,深度優先搜索的特點就是從一個位置直接搜下去,直到搜到末尾或者中途return

先擴展出深度。

dfs圖中遍歷的狀態會形成一棵搜索樹。(如果搜成了一般圖,那就說明剪枝不到位了)

一般認為,dfs的復雜度就是“搜索樹的大小 乘上 每一個狀態 下的復雜度”

自我感覺,dfs的更多時候,用途不在於搜索,而在於對結構的遍歷。

用途:

1.50%的暴力,2^n,n!的枚舉。

2.容斥。

3.遍歷。

dfs遍歷一棵樹(可能爆棧),(求dfs序,樹形dp等)

因為dfs會搜完一棵子樹再回溯,所以利用這個性質,dfn,dfn2,以及tarjan都可以成立。

利用遞歸的性質,從兒子回溯後,對這一層的檢查與更新,也是經常用到的。

4.配合BFS,尋找聯通塊

BFS:

最基本的遍歷圖的方法。一般用於搜索。

顧名思義,廣度優先搜索,就是先擴展整個圖的層數。

會從一個起點(多個起點)開始,不斷把周圍一層遍歷,

即,遍歷的狀態的層數總是連續的一段。

用途:

1.邊權為1的最短路。

這個其實是值得註意的,BFS的最短路是O(n+m)的,是所有的最短路中最快的。(有時那SPFA或者dij跑邊權為1的最短路,就浪費了~~~)

當然,必須邊權是1。

2.分層圖:
利用BFS的分層圖的性質,可以有層次地遍歷一個結構。

AC自動機的fail樹的構建:由於分層圖,而fail[i]一定長度比i小,即層的編號小,所以必然已經遍歷,沒有後效性。

DINIC算法,在分層圖上跑增廣路。可以保證復雜度。

問題:

1.DFS的劣勢明顯,會進入一個搜索子樹,遍歷完這棵搜索樹之後才會回溯。

如果這棵搜索樹對答案不能產生影響,那麽會大大降低效率。

更糟糕的,如果一棵子樹非常龐大(指數級增長),則直接TLE地飛起。

2.BFS的劣勢明顯,由於要廣度優先搜索,所以會遍歷完整個一層才會遍歷下一層。

如果一層很多,也會爆炸。

而且,必須記錄所有當前在隊列裏狀態的狀態信息。

如果狀態增多,搜索樹較大,空間和時間都沒有辦法保證。

對於這些bug,機智的人們創建了新的優化方法。

二、剪枝

剪枝,顧名思義,就是在dfs或者bfs中,把一棵搜索子樹直接砍去,不進行遍歷。

來達到復雜度的保證。

其實剪枝範圍可以很廣,A*,IDA*,甚至dp,我認為都可以叫剪枝。

而且剪枝也不一定用於搜索。

當然,一般情況下的剪枝,就是指用dfs搜索中的剪枝。

1.最優性剪枝。

最常見。最基本的,對於單增取min,單減取max,都可以穩定減去一些復雜度。

配合估價函數,對未來最少花費進行預估,通常可以大大增加效率。

2.可行性剪枝。

對於狀態搜索下去是否能合法的剪枝。

剪枝最重要的還是分析題目的性質。

例題:NOIP2004 蟲食算

Mayan遊戲

生日蛋糕

[學習筆記]搜索——模擬與dp的結合