Mímisbrunnr知恵の泉

← 数理最適化 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:代表的な組合せ問題 | 関連:局所探索と近傍

要点(BLUF)

概念 ── 何が「難しい」のか

最適化の難しさは「規模 nn に対して計算時間がどう伸びるか」で測る。多項式(n2, n3n^2,\ n^3)なら実用的、指数(2n, n!2^n,\ n!)なら手に負えない。組合せ最適化(代表的な組合せ問題)が難しいのは、選択肢が 指数的に増えるから。

graph TD
  P["P: 多項式時間で解ける (最短路・割当・LP)"] --> NP["NP: 解を多項式時間で検証できる"]
  NP --> NPC["NP完全: NPの中で最も難しい (NP かつ NP困難)"]
  NPH["NP困難: NPの全問題が帰着する難しさ"] --> NPC
  NP --> NPH2["TSP・ナップサック・集合被覆"]

P・NP・NP困難・NP完全

未解決問題 P ≟ NP:「検証できる問題は解けるか?」 多くの研究者は PNPP \ne NP と予想。もし正しければ、TSP のような NP 困難問題に 多項式時間の厳密アルゴリズムは存在しないことになる。

組合せ爆発を数値で見る

巡回セールスマン(TSP)の巡回路は (n1)!/2(n-1)!/2 通り、0/1 変数の部分集合は 2n2^n 通り。nn が増えると桁が暴走する。

import math

print(f"{'n':>3} | {'TSP巡回路数 (n-1)!/2':>22} | {'部分集合数 2^n':>16}")
for n in [5, 10, 15, 20, 25]:
    tsp = math.factorial(n-1) // 2     # TSPの異なる巡回路の数
    subsets = 2**n                     # 0/1がn個の組合せ数
    print(f"{n:>3} | {tsp:>22,d} | {subsets:>16,d}")

# n=25 のTSPを全探索したら? 10億(1e9)通り/秒 で評価できるとして
tours = math.factorial(24) // 2
years = tours / 1e9 / (60*60*24*365)
print(f"\nn=25 のTSP全探索: 巡回路 {tours:.3e} 通り, 所要 {years:.3e} 年")

実行結果:

  n |   TSP巡回路数 (n-1)!/2 |   部分集合数 2^n
  5 |                     12 |               32
 10 |                181,440 |            1,024
 15 |         43,589,145,600 |           32,768
 20 | 60,822,550,204,416,000 |        1,048,576
 25 | 310,224,200,866,619,719,680,000 |       33,554,432

n=25 のTSP全探索: 巡回路 3.102e+23 通り, 所要 9.837e+06 年

たった25都市の TSP でも、1秒に10億通り評価できる計算機で 約980万年かかる。これが「指数時間は実用にならない」の意味。全探索は無理なので、賢い枝刈り(分枝限定法)か、最適性を諦めた近似(メタヒューリスティクス 章目次)が要る。

難しさとどう折り合うか

NP 困難でも実務は止まらない。折り合いの付け方:

数式の直観的意味

NP 困難の本質は「検証は易しいが探索は難しい」の非対称性。解を1つ渡されれば正しさは多項式時間で確認できるのに、その解を 見つけるには指数的に広い空間を探さねばならない(PNPP\ne NP なら)。最適化が難しいのは、単に解を1つ見つけるのでなく「最良であることの証明」まで要るから ── これは「より良い解が存在しない」ことの確認で、緩和の上界(整数計画とは・LP緩和)が一致して初めて達成される。だから最適化の高速化は「探索を間引く(分枝)」と「上界を締める(カット・緩和)」の両輪になる。

⚠️ よくある誤解・落とし穴

関連ノート