求解最小环

对于一个无向图或有向图求解一个边权值最小的包括三个点的环。

Sightseeing trip

题目链接

题意:求解一个无向图的最小环

解法:由于是无向图,所以选择使用\(floyd\),然后利用\(floyd\)\(dp\)特性,然后就可以轻松求解了。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define ll long long
#define maxn 110
int n, m, ans;
ll a[maxn][maxn], dis[maxn][maxn];
int pos[maxn][maxn];
vector <int> path;
void getpath(int x, int y)
{
	if(pos[x][y] == 0) return;
	getpath(x, pos[x][y]);
	path.push_back(pos[x][y]);
	getpath(pos[x][y], y);
}
int main()
{
	ans = 1e9;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
	    for(int j = 1; j <= n; j++) a[i][j] = 1e9, a[i][j] *= 1e9, dis[i][j] = 1e9, dis[i][j] *= 1e9;
	for(int i = 1; i <= m; i++)
	{
		int u, v; long long w;
		scanf("%d%d%lld", &u, &v, &w);
		dis[u][v] = dis[v][u] = min(dis[u][v], w);
	    a[u][v] = a[v][u] = dis[u][v];
	}
	for(int k = 1; k <= n; k++)
	{
		for(int i = 1; i < k; i++)
		    for(int j = i + 1; j < k; j++)
		    {
			    if(dis[i][j] + a[i][k] + a[k][j] < ans)
				{
				    ans = dis[i][j] + a[i][k] + a[k][j];
					path.clear();
					path.push_back(i);
					getpath(i, j);
					path.push_back(j);
					path.push_back(k);	
				}
			}
		for(int i = 1; i <= n; i++)
		    for(int j = 1; j <= n; j++)
		    if(dis[i][j] > dis[i][k] + dis[k][j])
		    {
		        dis[i][j] = dis[i][k] + dis[k][j]; pos[i][j] = k;
		    }
	}
	if(ans == 1e9)
	{
		printf("No solution.\n");
		return 0;
	}
	for(int i = 0; i < path.size(); i++) printf("%d ", path[i]);
	return 0;
}

对于有向图,可直接枚举起点,用堆优化\(dijkstra\)求解单源最短路,从\(s\)点更新最短路,然后把\(s\)点的距离设为正无穷,当第二次访问到\(s\)时,\(d[s]\)就是经过\(s\)的最小环长度。

posted @ 2019-11-12 07:55  Akaina  阅读(130)  评论(0编辑  收藏  举报