思想:状压DP加Floyd。(跟TSP问题很像,只是对不同地点的路径加了一个Floyd处理。)
- DP状态:已经走过的城市集合,当前在哪一个城市。
- 转移方程:dp[s][i] = min(dp[s][i], dp[s ^ 1 << i][j] + dist[j][i]);(根据前面的城市更新当前的城市,s^1<<j表示集合s减去第j个城市)。
【注意】需要对只有一个城市的情况特判一下。if(n==1) then cout << 0 << endl;
【代码如下】
#include <iostream>
#include <cstring>
using namespace std;
int T;
int n, m;
int dist[18][18];
int dp[1<<16][17];
const int INF = 0x3f3f3f3f;
int main() {
cin >> T;
while (T--) {
int u, v, w;
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dist[i][j] = ((i==j)?0:INF);
}
}
while (m--) {
cin >> u >> v >> w;
u--;
v--;
if (dist[u][v] > w) {
dist[u][v] = w;
dist[v][u] = w;
}
}
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]);
}
}
}
memset(dp, 0x3f, sizeof(dp));
dp[1][0] = 0;
for (int s = 0; s < (1<<n); s++) {
for (int i = 0; i < n; i++) {
if (s & (1<<i)) {
for (int j = 0; j < n; j++) {
if (j != i && (s & (1<<j))) {
dp[s][i] = min(dp[s][i], dp[s ^ 1 << i][j] + dist[j][i]);
}
}
}
}
}
if (n == 1) { //这里需要特判一下n=1的情况
cout << 0 << endl;
continue;
}
int ans = INF;
for (int i = 1; i < n; i++) {
ans = min(ans, dp[(1<<n) - 1][i] + dist[i][0]);
}
cout << ans << endl;
}
return 0;
}