【POJ1734】Sightseeing trip
题目链接:https://www.acwing.com/problem/content/346/
题目大意:确定无向带权图上至少包含 3 个节点的最小环
solution
一道无向图上的最小环问题 , 考虑 \(Floyd\) , 设 \(i\) 到 \(j\) 间的道路长为 \(f[i][j]\) , 最短路径长 \(g[i][j]\) , 若每次 \(Floyd\) 最外层 遍历到 \(k\) 时 , \(g[i][j]\) 决定了 \(i\) 到 \(j\) 间经过节点编号不超过 \(k\) 的最短路径 , 不妨以 \(k\) 为环上的节点 , 枚举 \(i\) 和 \(j\) , 即是枚举 \(k\) 在环上的相邻节点 , 那么这个环的最小长度为\(f[i][k] + f[k][j] + g[i][j]\) , 这样就可以找出环上节点编号不超过 \(k\) 的最小环 , 由对称性 , 最终可以遍历到每一个最小环
拓展 : 对于有向图上的最小环 , 可以依次枚举起点 \(s\) , 再在 \(dijstra\) 中 \(s\) 向外拓展后 , 把 \(shortestpath[s]\) 设为极大值 , 最终的 \(shortestpath[s]\) 即为从 \(s\) 开始的最小环的长度 , 笔者在这不多加赘述
时间复杂度 : \(O(n^3)\)
code
#include<bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF) {
int RR = 1; FF = 0; char CH = getchar();
for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
FF *= RR;
}
inline void file(string str) {
freopen((str + ".in").c_str(), "r", stdin);
freopen((str + ".out").c_str(), "w", stdout);
}
const int N = 105;
int g[N][N], ans = INT_MAX, f[N][N];
int pos[N][N], n, m;
queue<int> path;
void get_path(int xi, int yi) {
if(pos[xi][yi] == 0) return;
get_path(xi, pos[xi][yi]);
path.push(pos[xi][yi]);
get_path(pos[xi][yi], yi);
}
int main() {
//file("");
int u, v, w;
read(n), read(m);
memset(g, 0x3f, sizeof(g));
memset(f, 0x3f, sizeof(f));
for(int i = 1; i <= n; i++) f[i][i] = g[i][i] = 0;
for(int i = 1; i <= m; i++) {
read(u), read(v), read(w);
g[u][v] = g[v][u] = min(g[u][v], w);
f[u][v] = f[v][u] = g[u][v];
}
ans = f[0][0];
for(int k = 1; k <= n; k++) {
for(int i = 1; i < k; i++)
for(int j = i + 1; j < k; j++)
if((long long)g[i][j] + f[i][k] + f[k][j] < ans) {
ans = g[i][j] + f[i][k] + f[k][j];
while(!path.empty()) path.pop();
path.push(i);
get_path(i, j);
path.push(j); path.push(k);
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(g[i][k] + g[k][j] < g[i][j]) {
g[i][j] = g[i][k] + g[k][j];
pos[i][j] = k;
}
}
if(path.empty()) {
puts("No solution.");
return 0;
}
while(!path.empty()) cout << path.front() << " ", path.pop();
cout << endl;
return 0;
}