求最小环的原理是dp的思想,我们以环中最大的节点作为断点,这样在求floyd的过程中,在更新之前,可以用i和k以及j和k相连的两条线路以及原先i和j在前k-1已经求出的最短路当作环进行比较
因为我们分割出了所有情况。而在求取方案的时候,我们设置一个pos数组,表示最短路的分割点,进行递归求取
#include<iostream> #include<cstring> using namespace std; const int N=200; const int inf=0x3f3f3f3f; int d[N][N]; int g[N][N]; int pos[N][N]; int path[N]; int n,m; int cnt; void get(int l,int r){ if(pos[l][r]==0) //到边界了,i=j return ; int x=pos[l][r]; get(l,x); path[cnt++]=x; get(x,r); } int main(){ cin>>n>>m; memset(d,0x3f,sizeof d); int i,j,k; for(i=1;i<=n;i++){ d[i][i]=0; } for(i=1;i<=m;i++){ int a,b,c; cin>>a>>b>>c; d[a][b]=d[b][a]=min(d[a][b],c); } int res=inf; memcpy(g,d,sizeof g); for(k=1;k<=n;k++){ for(i=1;i<k;i++){ for(j=i+1;j<k;j++){ if((long long)d[i][j]+g[i][k]+g[k][j]<res){ cnt=0; res=d[i][j]+g[i][k]+g[k][j]; path[cnt++]=k; path[cnt++]=i; get(i,j); path[cnt++]=j; } } } for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ if(d[i][j]>d[i][k]+d[k][j]){ d[i][j]=d[i][k]+d[k][j]; pos[i][j]=k; } } } } if(res==inf) cout<<"No solution."<<endl; for(i=0;i<cnt;i++){ cout<<path[i]<<" "; } cout<<endl; }