【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;
}



posted @ 2020-01-29 21:52  MagicDuck  阅读(225)  评论(0编辑  收藏  举报