版权声明:本人QQ 249712949 欢迎交流算法(请备注)。 https://blog.csdn.net/coord_/article/details/88956511
floyd
求最小环(正环)问题。注意和HDU 1217的区别。
这个题就是套路固定这么做的,这个题和负环完全没有一点关系。
是个中文题,题意就没啥可说了,这个题是个无向图,求一个至少有三个点的环,这个环在全图所有至少有三个点的环中长度最小(所谓环的长度就是绕着这个环走一圈,每条边的权值之和)。
套路就是在floyd
的第一层下面,第二三层上面,再加一个两层循环,用来枚举每两个点i,j
,首先保证i,j,k
三个互相不等,然后,因为是在原来二三层的上面,所以这时的d[i][j]
一定还没有被k
优化过,也就是说目前d[i][j]
中间一定没有k
点,所以从i
到j
,再找一条j
到k
的边和一条k
到i
的边,这就一定能保证是一条至少三个点的环路了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
using namespace std; // floyd求最小环(>=3) 就当板子吧
const int MAXN = 101;
const int INF = 1e9;
int N, M;
int g[MAXN][MAXN]; // 两点间边权
int d[MAXN][MAXN]; // 两点间最短路距离
int ans;
void init()
{
for (int i = 1; i <= N; i++)
{
for (int j = i; j <= N; j++)
{
if (i == j) g[i][j] = 0;
else g[i][j] = g[j][i] = INF;
}
}
ans = INF;
}
void floyd()
{
for (int k = 1; k <= N; k++)
{
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
if (g[j][k] != INF && g[k][i] != INF && k != i && k != j && i != j) // 防INF相加溢出,事实证明,不加会WA
{
ans = min(ans, d[i][j] + g[j][k] + g[k][i]);
}
}
}
for (int i = 1; i <= N; i++)
{
for (int j = i + 1; j <= N; j++) // 又不是求负环,让i,j重复没有用,而且因为是无向图,i,j是对称的
{
if (d[i][k] != INF && d[k][j] != INF && d[i][k] + d[k][j] < d[i][j])
{
d[i][j] = d[j][i] = d[i][k] + d[k][j];
}
}
}
}
}
int main()
{
int a, b, c;
for (; ~scanf("%d%d", &N, &M);)
{
init();
for (int i = 0; i < M; i++)
{
scanf("%d%d%d", &a, &b, &c);
g[a][b] = g[b][a] = min(g[a][b], c);
}
memcpy(d, g, sizeof g);
floyd();
if (ans == INF) printf("It's impossible.\n");
else printf("%d\n", ans);
}
return 0;
}