求最小权值的环。有重边。需要输出路径。
一种办法是,每次去掉一条边,然后求这边连接的两点之间的最短路,加上这条边的权,就是包含这条边的最小环。执行N次。
另一种办法是,直接用Floyd来求。
Floyd第k次循环,会求出经过k这点的最短路,所以在求经过k的最短路之前
若存在 点 i<k , j<k ,i!=j ,且i与k之间有路,j与k之间有路 的话,这就是一个环,
权值为 i 到 k 的距离 加上 j 到 k 的距离 加 i 到 j 的最短路(这个最短路中没有经过k以及比k大的节点)
所以只要在正常的Floyd第k次循环中加入一小段判断环的代码就行了。
int MinCir;//最小环值
vector<int> Path;//最小环路径
int dist[maxn][maxn];//邻接矩阵
int A[maxn][maxn]; //Floyd中用的存最短路
int path[maxn][maxn];//最短路径
int N,M;
int main(void)
{
while(cin>>N&&(~N)){
//预处理
For(i,N){
For(j,N){
if(i==j) dist[i][j]=0;
else dist[i][j]=inf;
path[i][j]=-1;
}
}
Path.clear();
cin>>M;
For(i,M) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(c<dist[a-1][b-1]){//去除重边,若有重边,去权值最小的
dist[a-1][b-1]=c;
dist[b-1][a-1]=c;
path[a-1][b-1]=a-1;
path[b-1][a-1]=b-1;
}
}
//Floyd计算最小环
MinCir=inf;
For(i,N){
For(j,N){
A[i][j]=dist[i][j];
}
}
For(k,N){
//求经过k的最小环
for(int i=0;i<k;i++){
for(int j=i+1;j<k;j++){
int D=A[i][j]+dist[i][k]+dist[j][k];//此时A[i][j]表示的最短路没有经过k点,所以保证是环。
if(D <MinCir){//如果找到了更小的环,保存路径。
MinCir=D;
Path.clear();
int t=j;
Path.push_back(j);
while(path[i][t]!=i){
Path.push_back(path[i][t]);
t=path[i][t];
}
Path.push_back(i);
Path.push_back(k);
}
}
}
<span style="white-space:pre"> </span>//正常的Floyd ,求经过k的最短路。
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
if(A[i][k]+A[k][j]<A[i][j]){
A[i][j]=A[i][k]+A[k][j];
path[i][j]=path[k][j];
}
}
}
}
//输出
if(MinCir>=inf) printf("No solution.\n");
else{
For(i,Path.size()){
printf("%d",Path[i]+1);
if(i==Path.size()-1) printf("\n");
else printf(" ");
}
}
}
return 0;
}