題目大意
n ≤ 17 個城市,m 條雙向路,每條有長度。
- 從城市 1 出發,遍歷所有城市並返回 1,求最小總路程。
解法:Floyd 預處理 + TSP DP
- Floyd-Warshall 算出任意兩點最短距離
dist[i][j]。
- 狀態
dp[mask][i]:已訪問集合為 mask(bitmask),當前在城市 i 的最小路程。
mask 第 k 位 = 1 表示城市 k+1 已訪問。
- 初始:
dp[1][0] = 0(城市 1 編號 0),其餘 INF。
- 轉移:
for mask from 1 to (1<
for i in 0..n-1 if (mask & (1<
for j in 0..n-1 if (!(mask & (1<
dp[mask | (1<
- 答案:
min_i dp[(1<。
完整代碼
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int dist[18][18];
int dp[1<<17][17];
int main() {
int n, m;
while (cin >> n >> m) {
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
dist[i][j] = (i==j?0:INF);
for (int i = 0; i < m; ++i) {
int u, v, w; cin >> u >> v >> w; --u; --v;
dist[u][v] = dist[v][u] = min(dist[u][v], w);
}
// Floyd
for (int k = 0; k < n; ++k)
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
// DP
int ALL = 1 << n;
for (int mask = 0; mask < ALL; ++mask)
for (int i = 0; i < n; ++i)
dp[mask][i] = INF;
dp[1][0] = 0;
for (int mask = 1; mask < ALL; ++mask) {
for (int i = 0; i < n; ++i) if (mask & (1<
複雜度
- Floyd:
O(n³),n ≤ 17 微秒級。
- DP:狀態
2^n × n ≈ 2.2M,轉移 O(n),總 O(n² 2^n) ≈ 38M,C++ 輕鬆通過。