题意:给定一个无向带权图,求其中长度大于等于3的最小圈(实际上长度等于2的圈就是重边,所以存边的时候忽略重边,只存储权值最小的边)
思路:Floyd的应用。找到圈的办法就是判断d[i][j] + map[i][k] + map[k][j] < INF是否成立,因为Floyd是按照结点的顺序更新最短路的,所以我们在更新最短路之前先找到一个连接点k,当前的点k肯定不存在于已存在的最短路d[i][j]的路径上,因为我们还没用这个k去更新最短路,相当于 (i -> k -> j -> j到i的最短路)这样一个环就找到了,接下来我们要记录路径,用path[i][j]表示在最短路i到j的路径上j的前一个结点,所以我们在更新最短路时也要更新这个点,原来的最短路是i -> j,现在变成了 i -> k -> j,所以有path[i][j] = path[k][j],因为要找最小环,所以不断更新找到环的权值,环更新一次,路径也要更新一次,路径更新时根据path数组迭代一下就ok了(http://www.2cto.com/kf/201502/377019.html)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define INF 0xfffffff
#define min(a,b) ((a)<(b)?(a):(b))
#define N 105
int g[N][N],f[N][N],path[N][N],res[N];
int n,m,len=0,ans = INF;
void floyd(){
int i,j,k,t;
for(k = 1;k<=n;k++){
for(i = 1;i<k;i++)
for(j = 1;j<i;j++)
if(f[i][j]+g[i][k]+g[k][j] < ans){
ans = f[i][j]+g[i][k]+g[k][j];
len = 0;
res[len++] = t = j;
while(path[i][t] != i){
res[len++] = path[i][t];
t = path[i][t];
}
res[len++] = i;
res[len++] = k;
}
for(i = 1;i<=n;i++)
for(j = 1;j<=n;j++)
if(f[i][j] > f[i][k]+f[k][j]){
f[i][j] = f[i][k]+f[k][j];
path[i][j] = path[k][j];
}
}
}
int main(){
int i,j,w,a,b;
scanf("%d %d",&n,&m);
for(i = 1;i<=n;i++)
for(j = 1;j<=n;j++){
f[i][j] = g[i][j] = INF;
path[i][j] = i;
}
for(i = 0;i<m;i++){
scanf("%d %d %d",&a,&b,&w);
if(w < g[a][b]){
g[a][b] = g[b][a] = w;
f[a][b] = f[b][a] = w;
}
}
floyd();
if(!len)
printf("No solution.\n");
else{
printf("%d",res[0]);
for(i = 1;i<len;i++)
printf(" %d",res[i]);
printf("\n");
}
return 0;
}