搜尋演算法是利用計算機的高效能來有目的的窮舉乙個問題解空間的部分或所有的可能情況,從而求出問題的解的一種方法。
現階段一般有列舉演算法、深度優先搜尋、廣度優先搜尋、a* 演算法、回溯演算法、蒙特卡洛樹搜尋、雜湊函式等演算法。
在大規模實驗環境中,通常通過在搜尋前,根據條件降低搜尋規模;根據問題的約束條件進行剪枝;利用搜尋過程中的中間解,避免重複計算這幾種方法進行優化。
平時大家寫的暴力也在搜尋的範疇之內
最基本的搜尋框架
各自有適用的場合
偽**(呂欣大佬手打):
void bfs(int s) }
} }eg:有乙個文字編輯器,它維護了乙個字串和乙個游標
字串中只包含 a ~ g,且每個字元最多隻出現一次
游標在字串開頭/結尾/兩字元之間
允許的操作:
將游標向前 / 後移動乙個字元,消耗 1 點體力
在游標前 / 後插入乙個字元(需保證它沒有出現過),消耗為 2
刪除游標前字元,消耗為 2
給定初始字串和游標位置,問將它轉化為目標字串最少多少步
解:用兩個佇列來維護bfs就可以啦!!!qaq
給定鬥地主的一組手牌,問用合法規則將它們全部打完,最少需要多少輪
多組詢問
n <= 23
解: 考慮預處理 dp[x][y][z][w] 表示分別有 x、y、z、w 種出現 4、3、2、1 次的牌,不出順子最少幾步打完
dfs 搜尋打順子的情況,結合 dp 計算答案
最優性剪枝
一種重要的優化搜尋的手段
如果搜尋的問題能分成兩部分,且兩部分能夠很高效的合併,那麼可以使用中途相遇法來大大提高搜尋的效率
已知 n 元高次方程:
\sum_ k[i] * x[i] ^ p[i] = 0
設未知數均為不大於 m 的正整數,求解的個數
n <= 6, m <= 150
解: 將前半部分的搜尋結果存入 hash 表
再搜後半部分
給定素數 m 和整數 a、b
解方程 a^x = b (mod m)
給出任意一組解,或者說明無解
a, b <= m <= 10^9
解: 設步長 m
那麼任意乙個解可以寫成 x = km + r
那麼 a^ = a^ * b (mod m)
列舉可能的 r,把左半部分扔進 hash 表
列舉可能的 m,嘗試尋找解
複雜度 o(m) + o(m / m) >= o(\sqrt)
給定 4 個長度為 n 的整數陣列,給定 m
求:從 4 個陣列中分別選乙個數 a, b, c, d,使得
abcd=1 (mod m)
的方案數
n <= 4000
啟發式搜尋又稱為有資訊搜尋,它是利用問題擁有的啟發資訊來引導搜尋,達到減少搜尋範圍、降低問題複雜度的目的,這種利用啟發資訊的搜尋過程稱為啟發式搜尋。
啟發式搜尋中應用最為廣泛的搜尋技巧當屬 a* 和 ida* 了
前者是 bfs 的啟法式版本,後者是前者的迭代加深版本
牛客國慶集訓派對Day2
題意 給出最大4096 64和64 4096的矩陣,其中有乙個矩陣只含有0和1,問你它們相乘所得到得矩陣所有元素異或 思路 一開始我想到的是能不能將01矩陣的一排都用二進位制表示,但是發現2的64次方大於4096,反而增大了複雜度,於是沒有做出這題,題解是將矩陣分塊,最多分成8塊,這樣01矩陣的種數...
省隊集訓DAY2
假設我們列舉數列中長度為len的區間,那麼如何判斷兩個數列可以匹配呢?對於提取的數列從小到大排序,從大到小排序,然後兩兩配對,如果所有的都滿足 h 那麼就可以匹配。應該算是貪心吧。這樣做的時間複雜度是o n le n loglen 還是上面的思想,我們如何快速判斷呢?假設我們確定了提取出的區間數列,...
國慶集訓Day1
題意 有 n 個數 a 1,a 2,a n 有m個數 b 1,b 2,b n 令 a a 1 times a 2 times times a n 令 b b 1 times b 2 times times b n 判斷 a 是否是 b 的倍數 輸入 n,m 輸出 yes no 做法 就是個一簡單的質...