給定完全圖 n ≤ 15,每點有權 w[i],每邊有權 map[i][j]。選擇恰好 m 個點構成子圖,在其上建立生成樹,使 (樹邊權和) / (所選點權和) 最小。輸出最優點集(編號遞增)。
n ≤ 15 ⇒ 所有 m 元子集數 C(15, m) ≤ 6435,完全可行。
對每個候選點集:
sumE。sumE / sumW,更新全局最優。vis[] 標記「已在 MST 中」與「不在候選集中」兩種狀態。原碼技巧:tmp[] 備份 vis[],Prim 內部修改 vis[],結束後 memcpy 還原。dis[i] 初始化為到起點的邊權(非集合點設 INF)。O(n²) Prim,n=15 瞬時完成。void dfs(int pos, int cnt, double sumW) {
if (cnt == m) {
double sumE = prim();
if (sumE / sumW < best) { best = sumE / sumW; memcpy(bestSet, vis, sizeof(vis)); }
return;
}
for (int i = pos; i <= n; ++i) if (vis[i]) {
vis[i] = 0; dfs(i, cnt+1, sumW + w[i]); vis[i] = 1;
}
}
vis[i]=1 表示「仍可選」,選中後設 0 並遞迴,回溯後恢復。pos 參數保證組合不重複、有序。C(15, m),每次 Prim O(n²)=225,總操作 < 200 萬,極快。最優點集編號以空格分隔,行末無多餘空格。原碼用 flag 控制首個前不印空格。
本題展示了「小規模圖上比率優化」的標準套路:枚舉分子(點集)→ 內層多項式算法求分母(MST)。n ≤ 15 使暴力枚舉成為最簡潔、最不易出錯的方案,無需分數規劃或參數搜尋等進階技巧。