题目链接

最小环 floyd

题意:包含至少3个点的最小环

思路:在i->j的一条最短路径上,只要额外加一个点k,i和j与k都有一条无向边,
就能形成路径为 i->j->k->i 的环
在floyd松弛边的过程中,不断的尝试在最短路上加多一个点 k,计算最小环的大小。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

typedef long long ll;

const int MaxnN = 100+10;
const int MaxnM = 2e5+10;
const int INF = 0x3f3f3f3f;
const ll LINF = 1e18;
ll cost[MaxnN][MaxnN], G[MaxnN][MaxnN];
ll path[MaxnN][MaxnN]; 
vector <int> p;
int main(void)
{
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= n; ++j) {
			if(i == j) cost[i][j] = G[i][j] = 0;
			else cost[i][j] = G[i][j] = LINF;
			path[i][j] = j;
		}
	}
	int u, v, w;
	for(int i = 0; i < m; ++i) {
		scanf("%d%d%d", &u, &v, &w);
		cost[u][v] = cost[v][u] = G[u][v] = G[v][u] = min(G[u][v], (ll)w);
	}
	ll ans = LINF; // 最小环大小 
	for(int k = 1; k <= n; ++k) {
		for(int i = 1; i < k; ++i) {
			for(int j = i+1; j < k; ++j) {
				if(ans > cost[i][j]+G[i][k]+G[k][j]) {
					ans = cost[i][j]+G[i][k]+G[k][j];
					// 存储路径 
					p.clear();
					for(int x = i; x != j; x = path[x][j]) p.push_back(x);
					p.push_back(j); p.push_back(k);
				}
			}
		}
		for(int i = 1; i <= n; ++i) {
			if(i == k) continue;
			for(int j = 1; j <= n; ++j) {
				if(j == k || i == j) continue;
				if(cost[i][j] > cost[i][k]+cost[k][j]) {
					cost[i][j] = cost[i][k]+cost[k][j];
					path[i][j] = path[i][k];
				}
			}
		}
	}
	if(ans == LINF) puts("No solution.");
	else for(int i = 0; i < p.size(); ++i) {
		if(i == p.size()-1) printf("%d\n", p[i]);
		else printf("%d ", p[i]);
	}
	return 0;
 }