题目链接
https://vjudge.net/problem/POJ-1734/origin
题意
求最小环输出路径
思路
上次偷懒没学最小环路径输出,这次栽了。。
回顾弗洛伊德最小环floyd外层k循环时,得到的dis[i][j]是只使用1—k-1的节点连接的i-j最短路,那么枚举i和j,k—i---(i-j最短路径)—j---k就是只使用前k个点的所有环路,枚举到n即可。
注意我们k—i---(i-j最短路径)—j---k中,i-j最短路径是跑出的dis数组的值,而k-i和j-k都是原来的路径,所以不能直接在原图上跑弗洛伊德,需要新开一个数组,而且要随着弗洛伊德的进行跑最小环代码。
关于路径输出,每次更新最小环,之前的路径就没用了,数组要清空。之后k–i--(…)–j加入即可,其中k-i和j-k是直达,直接加入即可,而i-j的需要用到弗洛伊德输出最短路的方法。
代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=150;
const int inf=0x1f1f1f1f;
int n,m;
int mp[maxn][maxn],dis[maxn][maxn],pre[maxn][maxn];
vector<int>path;
void get_path(int x,int y){
if(!pre[x][y])return;
get_path(x,pre[x][y]);
path.push_back(pre[x][y]);
get_path(pre[x][y],y);
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("D:\\code\\IO\\in.txt","r",stdin);
freopen("D:\\code\\IO\\out.txt","w",stdout);
#endif
memset(dis,0x1f,sizeof dis);
memset(mp,0x1f,sizeof mp);
cin>>n>>m;
for(int i=0;i<=n;i++)
dis[i][i]=0;
while(m--){
int u,v,w;
cin>>u>>v>>w;
mp[v][u]=mp[u][v]=min(mp[u][v],w);
dis[v][u]=dis[u][v]=min(dis[u][v],w);
}
int ans=inf;
for(int k=1;k<=n;k++){
for(int i=1;i<k;i++){
for(int j=i+1;j<k;j++){
if(ans>dis[i][j]+mp[i][k]+mp[k][j]){
ans=dis[i][j]+mp[i][k]+mp[k][j];
path.clear();
path.push_back(i);
get_path(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];
pre[i][j]=k;
}
}
}
}
if(ans==inf)
cout<<"No solution."<<endl;
else{
for(int i=0;i<path.size();i++){
cout<<path[i];
if(i!=path.size()-1) cout<<' ';
else cout<<endl;
}
}
}