將 N 張分值不同的郵票分成兩堆,使兩堆分值差最小。經典 0/1 背包 / 分割問題。目標:找出一堆分值和最接近總和一半 (V) 的組合。
#define max(a,b) a>b?a:b
int V, ans, n, w[110], sum[110]; // V=總和/2, ans=目前最佳解(≤V)
void dfs(int i, int cnt) { // i: 考慮第 i 個物品 (從 n 遞減至 1), cnt: 目前累積和
if (i == 0) { // 遞歸邊界:所有物品決策完畢
ans = max(ans, cnt);
return;
}
// ========== 關鍵剪枝條件 ==========
if (ans == V || cnt + sum[i] <= ans) return;
// ==================================
if (cnt + w[i] <= V) // 選擇第 i 個物品
dfs(i - 1, cnt + w[i]);
dfs(i - 1, cnt); // 不選擇第 i 個物品
}
int main() {
// ... 輸入 n, w[1..n] ...
// sum[i] = w[1] + ... + w[i] (前綴和)
V = sum[n] / 2;
dfs(n, 0);
printf("%d\n", sum[n] - 2 * ans); // 總和 - 2*較小堆 = 差值
}
程式碼中 `i` 從 `n` 遞減至 `1`。`sum[i]` 定義為 `w[1] + ... + w[i]`。當搜尋到第 `i` 層時,**剩餘未決策的物品正是 1~i 號**,其總和即 `sum[i]`。若 `i` 從 1 遞增至 n,則需用後綴和 `suffixSum[i] = w[i] + ... + w[n]`。
DFS 剪枝核心在於**計算理論上界**,若上界無法超越當前最佳解,果斷放棄該子樹。`cnt + sum[i] <= ans` 是利用「剩餘資源總和」作為上界的經典技巧,配合 `ans == V` 最優解提前終止,將指數搜尋剪枝至可接受範圍。理解上界推導邏輯,是解決組合優化問題的關鍵能力。