D110【模板】最短路→最小环 Floyd 算法 P10927 Sightseeing trip
D110【模板】最短路→最小环 Floyd 算法 P10927 Sightseeing trip_哔哩哔哩_bilibili
给一个无向图,输出最小环上的点。
Floyd 算法在最外层循环到点 $k$ 时(尚未更新 $d$ 时),$d_{i,j}$ 是从 $i$ 到 $j$ 且仅经过编号 $[1,k-1]$ 中的点的最短路
当前最小环中编号最大的顶点为 $k$,环上与 $k$ 相邻的两个点为 $i,j$,该环的长度为 $d_{i,j}+w_{i,k}+w_{j,k}$.枚举 $k$ 更新最小环
更新最短路时,用数组 $p[i][j]=k$ 记录从 $i$ 到 $j$ 的最短路经过 $k$ 点
更新最小环时,用数组 path[cnt] 记录 $i,k,j$ 三点,再递归获得 $j$ 到 $i$ 的最短路上的中间点
相关板子:
D04【模板】最短路 Floyd 算法 - 董晓 - 博客园
// 最短路→最小环 Floyd 算法 O(N^3) #include<bits/stdc++.h> using namespace std; const int N=110,INF=0x3f3f3f3f; int n,m,cnt,res=INF; int w[N][N],d[N][N]; int p[N][N],path[N]; void get_path(int i,int j){ //递归 i,j 之间的点 if(p[i][j]==0) return; int k=p[i][j]; get_path(i,k); path[++cnt]=k; get_path(k,j); } void Floyd(){ for(int k=1; k<=n; k++){ for(int i=1;i<k;i++) for(int j=i+1;j<k;j++) if(res>1ll*d[i][j]+w[i][k]+w[j][k]){ res=d[i][j]+w[i][k]+w[j][k]; //更新最小环 cnt=0; path[++cnt]=i; path[++cnt]=k; path[++cnt]=j; get_path(j,i); //获取j到i的最短路上的中间点 } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(d[i][j]>d[i][k]+d[k][j]){ d[i][j]=d[i][k]+d[k][j]; //更新最短路 p[i][j]=k; //记录从i到j的最短路经过k点 } } } int main(){ cin>>n>>m; memset(w,0x3f,sizeof w); for(int i=1;i<=n;i++) w[i][i]=0; //去自环 for(int a,b,c;m--;){ cin>>a>>b>>c; w[a][b]=w[b][a]=min(w[a][b],c); //存边权,去重边 } memcpy(d,w,sizeof d); Floyd(); if(res==INF) puts("No solution."); else for(int i=1;i<=cnt;i++) cout<<path[i]<<' '; }
浙公网安备 33010602011771号