一开始没想到是深搜,以为是最短路,后来用脑洞大开想到了最小费用流…
其实只要dfs一下,如果当前点为终点的时候,判断是否所有点都已被访问过,再比较cost和ans,如果cost比ans小,记录下所有点的前驱点,再路径还原即可。
由于其中一个人不想最后一个回家,因此去掉它和终点的连边即可。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
bool vis[6];
int d[6][6];
int prev[6];
int path[6];
int ans;
void dfs(int v, int cost) {
if (v == 5) {
bool ok = true;
for (int i = 1; i <= 5; i++) {
if (!vis[i]) {
ok = false;
break;
}
}
if (ok && cost < ans) {
ans = cost;
for (int i = 1; i <= 5; i++) {
path[i] = prev[i];
}
}
return;
}
for (int i = 1; i <= 5; i++) {
int tmp = prev[i];
if (d[v][i] && !vis[i]) {
vis[i] = true;
prev[i] = v;
dfs(i, cost + d[v][i]);
vis[i] = false;
prev[i] = tmp;
}
}
}
int main(int argc, char const *argv[]) {
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
scanf("%d", &d[i][j]);
}
}
d[3][5] = d[5][3] = 0;
d[1][5] = d[5][1] = 0;
ans = 50000 + 5;
vis[1] = true;
memset(prev, -1, sizeof(prev));
dfs(1, 0);
printf("%d\n", ans);
std::vector<int> v;
int t = 5;
for ( ; t != -1; t = path[t]) {
v.push_back(t);
}
std::reverse(v.begin(), v.end());
for (int i = 0; i < v.size(); i++) {
printf("%d%c", v[i], i == v.size() - 1 ? '\n' : ' ');
}
return 0;
}