多次元ナップサック

🔥 Vibe プロンプト

「多次元ナップサックを解決:アイテム(容積,重量,価値)、最大容積30、最大重量15、総価値を最大化。」

多次元ナップサック問題とは?

多次元ナップサック (MDKP) は、古典的な0/1ナップサックを複数のリソース制約に拡張したものです。現実のリソース配分はほとんどの場合、多次元的です:

| シナリオ | 次元 | |---------|------| | 🚚 トラック積載 | 容積 + 重量 | | ☁️ クラウドVM配置 | CPU + メモリ + 帯域幅 | | 💰 投資ポートフォリオ | 資本 + リスク + 流動性 | | 🏗️ プロジェクト選択 | 予算 + 時間 + 人員 |

数学的定式化

最大化:  Σ(vᵢ × xᵢ)           ← 総価値を最大化
制約:
  Σ(wᵢ₁ × xᵢ) ≤ W₁              ← 容積制約
  Σ(wᵢ₂ × xᵢ) ≤ W₂              ← 重量制約
  xᵢ ∈ {0, 1}                    ← 各アイテムは取るか取らないか

実装

from ortools.sat.python import cp_model

# アイテム: (容積, 重量, 価値)
items = [
    (10, 5, 100),   # アイテム0: 小型、軽量、中価値
    (15, 8, 150),   # アイテム1: 中型、中重量、高価値
    (8, 3, 80),     # アイテム2: 小型、軽量、良価値
    (20, 12, 200),  # アイテム3: 大型、重量、最高価値
    (12, 7, 120),
    (6, 4, 60),
    (18, 10, 180),
    (14, 9, 140),
]

max_volume = 30
max_weight = 15

model = cp_model.CpModel()
n = len(items)

x = [model.NewBoolVar(f'x_{i}') for i in range(n)]

# 制約
model.Add(sum(items[i][0] * x[i] for i in range(n)) <= max_volume)
model.Add(sum(items[i][1] * x[i] for i in range(n)) <= max_weight)

# 目的: 価値最大化
model.Maximize(sum(items[i][2] * x[i] for i in range(n)))

solver = cp_model.CpSolver()
status = solver.Solve(model)

if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
    print(f"最大価値: {int(solver.ObjectiveValue())}")
    selected = [i for i in range(n) if solver.Value(x[i])]
    total_vol = sum(items[i][0] for i in selected)
    total_wt = sum(items[i][1] for i in selected)
    print(f"選択アイテム: {selected}")
    print(f"総容積: {total_vol}/{max_volume}")
    print(f"総重量: {total_wt}/{max_weight}")
    
    # 価値密度分析
    print(f"\n価値密度分析:")
    for i in range(n):
        vol, wt, val = items[i]
        density = val / (vol + wt)
        mark = "✅" if i in selected else "❌"
        print(f"  アイテム{i}: 密度={density:.2f} {mark}")

3次元ナップサックへの拡張

# (容積, 重量, コスト, 価値)
items_3d = [(10, 5, 100, 100), (15, 8, 120, 150), (8, 3, 60, 80), (20, 12, 180, 200)]
max_vol, max_wt, max_cost = 30, 15, 300
model.Add(sum(items_3d[i][2] * x[i] for i in range(n)) <= max_cost)

比較: 古典 vs 多次元

| 項目 | 古典0/1ナップサック | 多次元 | |------|--------------------|--------| | 制約数 | 1 (重量) | 2+ (重量、容積、コスト…) | | 複雑さ | NP困難(疑似多項式) | 強NP困難 | | DP可能 | Yes (O(nW)) | No (次元の呪い) | | CP-SAT適合 | Yes | Yes(得意分野!) | | 現実適合度 | 限定的 | 非常に良い |

実世界の応用

1. トラック積載

容積(トレーラー容量)と重量(車軸制限)の両方を考慮して貨物価値を最大化。

2. クラウドリソース配分

CPUコア、メモリ(GB)、ネットワーク帯域幅の制限内でデプロイするサービス数を最大化。

3. 投資ポートフォリオ

資本予算、リスク許容度、流動性要件の制約内で期待リターンを最大化する銘柄を選択。

4. プロジェクトポートフォリオ管理

予算($)、エンジニアリング時間(人月)、戦略的適合性スコアの制約内で資金提供するプロジェクトを選択。

まとめ

  • MDKP はナップサックを複数リソース次元に拡張
  • 強NP困難 — 疑似多項式DP解は存在しない
  • CP-SAT は小〜中規模インスタンスに最適
  • 現実のリソース配分はほとんどの場合多次元的
  • 3+次元もCP-SATで問題なく処理可能(制約を追加するだけ)

完全なチュートリアルをロック解除

このチャプターは有料コンテンツです。プロジェクトに参加して、10以上の神レベルのPromptや実際のソースコード例を含む、5000字以上の深い分析をロック解除してください!