背包問題與選題最佳化

實戰:預算分配

你是一家新創公司的 CTO,有 500 萬的技術預算。面對 10 個可能的技術投資項目,每個項目有不同的成本與預期回報,如何分配預算才能最大化總回報?

from ortools.sat.python import cp_model

# 項目資料
projects = [
    ("AI 客服", 150, 400),
    ("數據平台", 200, 350),
    ("App 開發", 180, 300),
    ("SEO 優化", 50, 180),
    ("績效系統", 120, 250),
    ("自動化測試", 80, 200),
    ("安全稽核", 60, 150),
    ("國際化", 100, 220),
    ("API 平台", 160, 280),
    ("BI 儀表板", 90, 190),
]

budget = 500  # 萬

model = cp_model.CpModel()

x = [model.NewBoolVar(f"x_{i}") for i in range(len(projects))]

# 預算限制
model.Add(sum(projects[i][1] * x[i] for i in range(len(projects))) <= budget)

# 相依性:如果選 AI 客服,必須也選數據平台
model.Add(x[0] <= x[1])

# 互斥:App 開發與 API 平台只能選一個
model.Add(x[2] + x[8] <= 1)

# 目標:最大化回報
model.Maximize(sum(projects[i][2] * x[i] for i in range(len(projects))))

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

if status == cp_model.OPTIMAL:
    print(f"\n=== 預算分配結果 ===")
    print(f"最佳總回報: {int(solver.ObjectiveValue())} 萬")
    print(f"預算上限: {budget} 萬")
    
    total_cost = 0
    for i, (name, cost, ret) in enumerate(projects):
        if solver.Value(x[i]):
            total_cost += cost
            print(f"✅ {name}: 成本 {cost}萬, 回報 {ret}萬")
    print(f"\n總使用預算: {total_cost} 萬")
else:
    print("無法找到最佳解")

擴展:投資組合最佳化

同樣的模型可應用於股票選擇:

# 股票資料
stocks = [
    ("AAPL", 180, 0.25),  # (名稱, 股價, 預期報酬率)
    ("GOOGL", 140, 0.20),
    ("MSFT", 330, 0.22),
    ("AMZN", 150, 0.30),
    ("TSLA", 250, 0.35),
]

max_investment = 1000  # $1M

# 精選 3 支股票
model.Add(sum(x[i] for i in range(len(stocks))) == 3)

# 單支股票不超過 60%
for i in range(len(stocks)):
    model.Add(stocks[i][1] * x[i] <= max_investment * 0.6)

其他應用場景

| 場景 | 說明 | |------|------| | 人員招募 | 預算內選擇最佳候選人組合 | | 廣告投放 | 預算限制下選擇最高 ROI 的渠道 | | 產品開發 | 有限資源下選擇最具影響力的功能 | | 庫存採購 | 資金限制內選購最佳商品組合 |

總結

| 面向 | 詳情 | |------|------| | 問題 | 預算內選擇項目以最大化回報 | | 限制類型 | 預算、相依性、互斥、數量下限 | | CP-SAT | 自然處理所有限制類型 | | ROI 分析 | 從求解結果自動計算 | | 擴展 | 投資組合、招募、資源分配 |

組合最佳化課程完成!🎉

  • ✅ 排箱問題
  • ✅ 工作排程
  • ✅ 多維度背包
  • ✅ 2D 切割
  • ✅ 預算分配
  • ✅ 相依性與互斥限制
  • ✅ 投資組合最佳化


背包問題:有限資源下的最佳選擇

背包問題(Knapsack)是最經典的 NP-hard 問題之一。想像你有一個背包,容量有限,你要從一堆物品中選出總價值最高的組合。

背包問題的變體

| 類型 | 限制 | 解法 | |:----|:----|:----| | 0/1 Knapsack | 每個物品只能選或不選 | DP:O(nW) 偽多項式時間 | | Fractional Knapsack | 物品可以分割 | 貪婪:按價值/重量比排序 | | Unbounded Knapsack | 每個物品可以取無限次 | DP:O(nW) | | Multi-dimensional | 多個限制條件(重量+體積) | DP:O(nW₁W₂) |

在真實世界的應用

  • 廣告投放:有限預算下選擇最高轉換率的廣告組合
  • 投資組合:有限資金下選擇最佳報酬的投資標的
  • 資源分配:有限伺服器資源下選擇要執行的任務
  • 物流裝載:有限載重下裝載最高價值的貨物

課程總結

這堂組合最佳化課你學到了排箱、排程、TSP、Cutting & Packing 和背包問題——五個最經典的 NP-hard 問題。每個問題都有對應的 CP-SAT 精確解法或啟發式近似演算法,你可以根據問題規模選擇適合的策略。

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!