求最小权值的环。有重边。需要输出路径。
一种办法是,每次去掉一条边,然后求这边连接的两点之间的最短路,加上这条边的权,就是包含这条边的最小环。执行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; }