供應鏈網路設計
問題描述
你是一家中型電商的老闆,要決定在台灣設立幾個倉庫、分別在哪個城市、每個倉庫服務哪些區域,才能讓總成本(倉庫租金 + 運輸成本)最低?
設施選址問題 (Facility Location Problem)
import pulp
import math
# === 候選倉庫位置 ===
warehouses = ["台北", "台中", "高雄", "花蓮"]
# === 服務城市 ===
cities = ["台北", "新北", "桃園", "新竹", "台中", "彰化", "雲林",
"嘉義", "台南", "高雄", "屏東", "宜蘭", "花蓮", "台東"]
# === 資料 ===
# 倉庫固定成本(月租金,萬元)
fixed_cost = {"台北": 50, "台中": 30, "高雄": 25, "花蓮": 15}
# 倉庫容量(件/月)
capacity = {"台北": 10000, "台中": 8000, "高雄": 8000, "花蓮": 4000}
# 城市需求(件/月)
demand = {
"台北": 3000, "新北": 2500, "桃園": 2000, "新竹": 1500,
"台中": 2800, "彰化": 1200, "雲林": 800, "嘉義": 1000,
"台南": 2000, "高雄": 2500, "屏東": 800, "宜蘭": 600,
"花蓮": 500, "台東": 300
}
# 運輸成本(每件每公里)
cost_per_km_per_unit = 0.5
# 距離矩陣(公里)
distance = {
("台北", "台北"): 0, ("台北", "新北"): 20, ("台北", "桃園"): 40,
("台北", "新竹"): 80, ("台北", "台中"): 180, ("台北", "彰化"): 200,
("台北", "雲林"): 240, ("台北", "嘉義"): 260, ("台北", "台南"): 310,
("台北", "高雄"): 350, ("台北", "屏東"): 370, ("台北", "宜蘭"): 60,
("台北", "花蓮"): 180, ("台北", "台東"): 350,
("台中", c): abs(distance.get(("台北", c), 999) - 180) if distance.get(("台北", c)) else 999
for c in cities
}
# 建立問題
prob = pulp.LpProblem("供應鏈網路設計", pulp.LpMinimize)
# 變數:y[w] = 1 表示選擇倉庫 w
select = {w: pulp.LpVariable(f"select_{w}", cat="Binary") for w in warehouses}
# 變數:x[w][c] = 從倉庫 w 運送到城市 c 的數量
ship = {}
for w in warehouses:
for c in cities:
ship[(w, c)] = pulp.LpVariable(f"ship_{w}_{c}", lowBound=0, cat="Continuous")
# 目標:總成本 = 倉庫固定成本 + 運輸成本
prob += (
pulp.lpSum(fixed_cost[w] * select[w] for w in warehouses) +
pulp.lpSum(ship[(w, c)] * distance.get((w, c), 999) * cost_per_km_per_unit
for w in warehouses for c in cities)
)
# 限制:每個城市的需求必須滿足
for c in cities:
prob += pulp.lpSum(ship[(w, c)] for w in warehouses) >= demand[c]
# 限制:倉庫產能限制
for w in warehouses:
prob += pulp.lpSum(ship[(w, c)] for c in cities) <= capacity[w] * select[w]
# 求解
prob.solve()
print(f"\n=== 供應鏈網路設計結果 ===")
print(f"求解狀態: {pulp.LpStatus[prob.status]}")
print(f"總成本: {pulp.value(prob.objective):.2f} 萬元/月")
print(f"\n選擇的倉庫:")
for w in warehouses:
if select[w].value() == 1:
print(f" ✅ {w} (固定成本: {fixed_cost[w]} 萬元/月)")
print(f"\n配送計畫:")
for w in warehouses:
if select[w].value() == 1:
total = sum(ship[(w, c)].value() for c in cities)
print(f"\n{w} 倉庫 (總出貨: {int(total)} 件):")
for c in cities:
qty = ship[(w, c)].value()
if qty and qty > 0:
dist_val = distance.get((w, c), 999)
cost = qty * dist_val * cost_per_km_per_unit
print(f" → {c}: {int(qty)} 件 (距離 {dist_val}km, 運費 {cost:.0f} 元)")
更多實作範例
使用 PuLP 求解
from pulp import *
# 定義問題
prob = LpProblem("Constrained Optimization", LpMaximize)
# 決策變數
x = LpVariable("x", 0, 10)
y = LpVariable("y", 0, 10)
# 目標函數
prob += 3*x + 4*y
# 限制條件
prob += 2*x + y <= 8
prob += x + 2*y <= 8
# 求解
prob.solve()
print(f'Status: {LpStatus[prob.status]}')
print(f'x = {value(x)}, y = {value(y)}')
print(f'Objective = {value(prob.objective)}')
應用場景
- 資源分配:在有限預算下最大化產出
- 排程問題:最小化工廠閒置時間
- 投資組合:在風險限制下最大化報酬
供應鏈網路設計的關鍵洞察
供應鏈網路設計(Supply Chain Network Design)是 ILP 在真實世界中最有價值的應用之一。一個好的網路設計可以幫企業節省數百萬的物流成本。
模型中的權衡
| 要權衡的項目 | 增加倉庫的影響 | 減少倉庫的影響 | |:-----------|:------------|:------------| | 運輸成本 | 下降(離客戶更近) | 上升(距離更遠) | | 倉庫固定成本 | 上升(更多租金/人力) | 下降 | | 服務水準 | 提升(24h 到貨率更高) | 下降 | | 庫存成本 | 上升(更多安全庫存) | 下降(集中庫存) |
為什麼這不是簡單的問題?
直覺上你可能覺得「倉庫越多越好」,但從上面的表格可以看到——每個決策都有 trade-off。ILP 的價值就在於幫你找到總成本最低的平衡點,而不是靠感覺決定。
敏感度分析
求解後可以問:「如果台北的租金漲 20%,結果會變嗎?」只要改變 fixed_cost 參數重新求解——ILP 可以快速回答這種 what-if 問題。
下一章預告:投資組合最佳化
供應鏈網路最佳化的是實體的物流。下一章的投資組合最佳化的是財務的資產配置——如何在不同風險和報酬的資產之間分配資金。