1971 - Cook 的 NP-完全理論(計算複雜度的分水嶺)#
案件摘要#
1971 年,Stephen Cook(1939–) 在 STOC 會議發表 The Complexity of Theorem-Proving Procedures:
Cook 定理:
P vs NP 的問題(千禧年七大問題之一,獎金 100 萬美元):
1982 年,Cook 獲得圖靈獎—— 這是計算理論 50 年來最重要的未解問題。
前因 -- 為什麼會有這個案子#
- 多項式 vs 指數(1950s–1960s):
- 有些演算法快(多項式):排序 \(O(n\log n)\) 、最短路徑 \(O(V^2)\) ;
- 有些演算法慢(指數):旅行推銷員 \(O(2^n)\) 、子集合和 \(O(2^n)\) 。
- Cobham 的類別(1964): Alan Cobham(1964)提出多項式時間是「高效計算」的數學定義:
這是「快 vs 慢」的分界線(雖然 \(n^{100}\) 也是多項式——理論的抽象)。 - Cook 的洞察(1971): Cook 在研究定理證明的複雜度時,發現:
- Levin 的平行發現(1973): Leonid Levin(蘇聯)在 1973 年獨立發現了同一理論—— Cook–Levin 定理(冷戰時代的雙重發現,與 Lobachevsky–Bolyai 相呼應)。
- Karp 的 21 個問題(1972): Richard Karp(1985 圖靈獎)把 Cook 的理論發揚光大—— 證明了 21 個經典問題都是 NP-完全的:
線索與推理 -- 數學式、程式、理論#
第一條線索:P、NP、NP-完全的定義#
| 類別 | 定義 | 例子 |
|---|---|---|
| P | 多項式時間可解 | 排序、最短路徑、線性規劃 |
| NP | 多項式時間可驗證 | SAT、TSP、圖著色 |
| NP-完全 | NP 中「最難」的 | SAT、3-SAT、TSP(決策版) |
| PSPACE | 多項式空間可解 | 棋類遊戲 |
問題:反向是否成立?
若成立:密碼學崩潰(RSA 可破)、最佳化全解; 若不成立(多數人相信):有些問題原理上無法快速求解。
第二條線索:Cook 定理(SAT 是 NP-完全)#
定理(Cook–Levin, 1971/1973):
證明大綱(「編碼計算過程」): 1. 對任何 NP 問題 \(L\) 與輸入 \(x\) ,存在非決定性圖靈機 \(M\) 在 \(n^k\) 時間內驗證; 2. 把 \(M\) 在 \(n^k\) 步內的整個計算過程編碼成一個布林公式 \(\phi_{M,x}\) : - 變數 = 「在第 \(t\) 步,紙帶第 \(i\) 格的符號是 \(\sigma\) 」; - 子句 = 機器的轉移規則(每一步的合法性); 3.
- 構造 \(\phi\) 只需多項式時間——故 \(L \le_p\) SAT。
第三條線索:歸約與 NP-完全的傳播(Karp 1972)#
多項式歸約:
性質:
Karp 的 21 個歸約(1972):
一個鏈條把 21 個問題全部連到 SAT—— NP-完全的「傳染病」(至今發現數千個 NP-完全問題)。
Python:SAT、3-SAT 與 NP-完全的驗證#
from itertools import product
# 1) SAT:暴力解(2^n,指數時間)
def sat_brute(clauses, n_vars):
"""clauses: 子句列表(每個子句是變數索引列表,正=xi,負=¬xi)"""
for assign in product([False, True], repeat=n_vars):
if all(any(assign[abs(l)-1] == (l > 0) for l in clause) for clause in clauses):
return assign
return None
# 2) 3-SAT 的例子(3 個文字一個子句)
clauses = [[1, 2, 3], [-1, 2, 3], [1, -2, 3], [-1, -2, -3]]
print("3-SAT 的暴力解(2^n 時間):")
for n_vars in [3, 5]:
if n_vars == 3:
c = clauses
else:
c = clauses + [[2, 4, 5], [-3, -4, -5], [1, 4, -5], [-2, -5, 4]]
import time
import itertools as it
result = sat_brute(c, n_vars)
n_combos = 2**n_vars
print(f" {n_vars} 個變數,{len(c)} 個子句:{n_combos} 種組合")
if result:
print(f" 可滿足!指派 = {[int(v) for v in result]}")
else:
print(f" 不可滿足")
# 3) 指數爆炸的驗證(2^n 的成長)
print("\n指數爆炸(2^n 的成長):")
for n in [10, 20, 30, 40, 50]:
print(f" n = {n}: 2^n = {2**n:>15} 種組合")
if n == 30:
print(f" (10 億種——已不可行)")
if n == 50:
print(f" (10^15 種——即使每秒 10 億次也要 12 天)")
# 4) 歸約:3-SAT → 頂點覆蓋(Karp 1972 的歸約之一)
print("\n歸約(3-SAT → 頂點覆蓋,Karp 1972):")
# 對每個子句建一個三角形,變數對建一對邊
def reduce_3sat_to_vc(clauses, n_vars):
"""歸約:多項式時間的圖構造"""
edges = []
node_id = n_vars # 子句節點從 n_vars 開始
clause_nodes = []
for i, clause in enumerate(clauses):
a, b, c = node_id, node_id+1, node_id+2
clause_nodes.append((a, b, c))
edges += [(a,b), (b,c), (a,c)] # 三角形
node_id += 3
# 變數節點與子句節點的連接
for i, clause in enumerate(clauses):
for j, lit in enumerate(clause):
var = abs(lit) - 1
edges.append((clause_nodes[i][j], var))
k = n_vars + len(clauses) # 覆蓋大小
return edges, k
edges, k = reduce_3sat_to_vc(clauses, 3)
print(f" 3 個子句 → 圖:{len(edges)} 條邊,覆蓋大小 k = {k}")
print(f" 構造時間 = O(子句數 × 文字數)(多項式 ✓)")
print(" → 3-SAT 可滿足 ⟺ 圖有大小 k 的頂點覆蓋")
print(" → 解決頂點覆蓋就能解決 3-SAT(NP-完全的傳播)")
# 5) P vs NP 的意義
print("\nP vs NP(千禧年問題,1971 Cook):")
print(" P:多項式時間可解(排序、最短路徑)")
print(" NP:多項式時間可驗證(SAT、TSP)")
print(" P ⊆ NP;問題:P = NP?")
print(" 若 P = NP:密碼學崩潰(RSA 可破)、最佳化全解")
print(" 若 P ≠ NP:有些問題原理上無法快速求解(多數人相信)")
print(" → 這是計算理論最重要的未解問題(100 萬美元獎金)")
3-SAT 的暴力解(2^n 時間):
3 個變數,4 個子句:8 種組合
可滿足!指派 = [0, 0, 1]
5 個變數,8 個子句:32 種組合
可滿足!指派 = [0, 0, 1, 1, 0]
指數爆炸(2^n 的成長):
n = 10: 2^n = 1024 種組合
n = 20: 2^n = 1048576 種組合
n = 30: 2^n = 1073741824 種組合
(10 億種——已不可行)
n = 40: 2^n = 1099511627776 種組合
n = 50: 2^n = 1125899906842624 種組合
(10^15 種——即使每秒 10 億次也要 12 天)
歸約(3-SAT → 頂點覆蓋,Karp 1972):
3 個子句 → 圖:24 條邊,覆蓋大小 k = 7
構造時間 = O(子句數 × 文字數)(多項式 ✓)
→ 3-SAT 可滿足 ⟺ 圖有大小 k 的頂點覆蓋
→ 解決頂點覆蓋就能解決 3-SAT(NP-完全的傳播)
P vs NP(千禧年問題,1971 Cook):
P:多項式時間可解(排序、最短路徑)
NP:多項式時間可驗證(SAT、TSP)
P ⊆ NP;問題:P = NP?
若 P = NP:密碼學崩潰(RSA 可破)、最佳化全解
若 P ≠ NP:有些問題原理上無法快速求解(多數人相信)
→ 這是計算理論最重要的未解問題(100 萬美元獎金)
結案 -- 後果與影響#
- 計算複雜度的分水嶺(1971):
Cook 的發現把「演算法的分析」(Knuth 1968)推到了極致—— 不只分析「這個演算法多快」,而是問「這個問題原理上能多快」:
- NP-完全的傳染病(1972–):
NP-完全的問題無所不在: - 物流:TSP、車輛路徑(VRP); - 排程:課表排程、工作排程; - 晶片設計:電路佈局、通道分配; - AI:規劃問題、SAT 求解器; - 生物資訊:蛋白質折疊、基因組比對。
- 密碼學的依賴(1976–):
RSA 的安全性基於「質因數分解沒有多項式演算法」—— 若 P = NP,RSA 崩潰—— 整個數位世界的安全依賴於 P ≠ NP(見「2002-RSA公開金鑰.md」)。 - 量子計算的插入(1994–2000): - Shor(1994):質因數分解在量子電腦上有多項式演算法—— RSA 的威脅; - 姚期智(2000 圖靈獎):量子通訊複雜度—— 量子計算的理論基礎(見「2000-姚期智量子計算.md」)。
- 千禧年問題(2000):
至今未解——這是計算理論的「聖杯」: - 多數複雜度學家相信 P ≠ NP(Poll 的調查,2002/2019); - 證明的困難:需要新的數學工具(自然證明障礙、相對化障礙)。 - Cook 的後續(1982 圖靈獎): Cook 1982 年獲圖靈獎——他的演講主題是計算複雜度的展望; 他與 Reckhow 進一步研究了證明系統的複雜度(propositional proof complexity)。 - 歷史定位:Cook 是「計算的邊界」的發現者——
一句話:有些問題容易驗證但難求解——這是原理,不是巧合。
關鍵人物與文獻#
- S. A. Cook:The Complexity of Theorem-Proving Procedures(1971);1982 圖靈獎。
- L. A. Levin:Universal search problems(1973)——平行發現(Cook–Levin 定理)。
- R. M. Karp:Reducibility Among Combinatorial Problems(1972)——21 個 NP-完全問題;1985 圖靈獎。
- A. Cobham:The intrinsic computational difficulty of functions(1964)——多項式時間的定義。
- P. Shor:量子因數分解(1994)——RSA 的威脅。
- 相關案件:
1936-圖靈機.md、1968-克努特演算法藝術.md、2002-RSA公開金鑰.md、2000-姚期智量子計算.md。