题目描述
给出一张图,求这幅图的最小环。
思路
我们考虑Floyd算法的过程,dp[i][j][k]表示的是经过编号不超过k的节点,从i到j的最短路径,而用滚动数组压掉一维。所以dp[i][j]+a[j][k]+a[k][i]就是由不超过k的几点组成的经过节点k的最小环,跑一遍Floyd即可。对于输出路径,我们用pos[i][j]=k记录i到j的最短路径的经过节点,我们可以这样不断分解得到路径,就得到i到j的路径,再加上(j,k)和(k,i)两条边即可。
代码
#include <bits/stdc++.h> using namespace std; const int INF=100000000; int pos[220][220],mp[220][220],dis[220][220]; vector<int>ans; void get_ans(int x,int y) { int k=pos[x][y]; if(k==0)return ; get_ans(x,k); ans.push_back(k); //分割求路径 get_ans(k,y); } int main() { 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)mp[i][j]=dis[i][j]=INF; else mp[i][j]=dis[i][j]=0; for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); mp[x][y]=mp[y][x]=min(mp[x][y],z);//防止重边 dis[x][y]=dis[y][x]=mp[x][y]; } int sum=INF; for(int k=1;k<=n;k++) { for(int i=1;i<=k-1;i++) for(int j=1;j<=k-1;j++) if(i^j&&dis[i][j]+mp[i][k]+mp[k][j]<sum) { sum=dis[i][j]+mp[i][k]+mp[k][j]; ans.clear(); ans.push_back(i); get_ans(i,j); //得到i、j间的路径 ans.push_back(j); ans.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]; pos[i][j]=k; //记录中间节点 } } if(sum==INF){printf("No solution.");return 0;} for(int i=0;i<ans.size();i++) printf("%d ",ans[i]); return 0; }