暴力法、窮舉搜尋與回溯

完全列舉(complete enumeration)

完全列舉是暴力法背後的承諾:把一個集合的每一個成員列出來,每個恰好一次,一個不漏、一個不重。想像你在念一份賓客名單——如果你真的把每個名字恰好念一次,你就能確定地回答某人是否在名單上,或算出總共有幾位,因為沒有任何一個從你眼前溜走。

這套紀律有兩半,兩者都必須成立。不遺漏是指每個合法候選都出現在你的列舉中;這正是你能信任「否」這個答案的根據——你之所以能說「無解」,是因為你真的把它們全看過了。不重複是指每個候選最多出現一次;這是讓計數誠實、避免白做工的關鍵。一個正確的列舉程序通常以構造方式同時證明這兩點:它替候選定下一個順序(號碼按數值順序、子集合或排列按字典序),並從頭走到尾,於是用歸納法可知每個候選都被走訪,而順序保證不重複。

把列舉看成「在一個結構化集合上的巡迴」,它就是窮舉搜尋。它最大的長處是:完備性給你確定性——對判定、計數、最佳化問題都能給出精確答案。它最大的弱點是規模:那些重要的集合(所有子集合、所有排列、所有著色)通常有 2^n、n! 或 k^n 個成員,所以一次完整巡迴只在 n 很小時可行。看出集合的結構——並學會在不破壞完備性的前提下跳過它一整片區域——正是本領域的核心技能。

要判定 {3, 7, 8, 12} 是否有某個子集合加總為 15,就以固定順序列舉全部 2^4 = 16 個子集合,逐一相加。你會遇到 {3, 12} 與 {7, 8},兩者都加總為 15。因為列舉是完全的,假如沒有任何一個加總為 15,你就能確定地宣告「不存在這樣的子集合」。

完備性正是讓「否」這個答案值得信任的原因——你得靠「一個不漏」才掙得到它。

完全列舉保證答案正確,卻不保證可用的執行時間;對大小為 2^n 或 n! 的集合,一次完整巡迴雖然正確,但超過相當小的 n 之後就慢得天文。

又称
exhaustive enumerationexhaustive search窮舉全列舉