zoukankan      html  css  js  c++  java
  • URAL1004 Sightseeing Trip Floyd 最小环

    题意:求有权无向图的最小环,环至少包括三个点。

    思路:

    设map[i,j]表示i到j的的距离。输入有重边,在处理输入的时候只保存最短边。

    取环中一个点k,左右点是ij则map[i,k]和map[k,j]是固定的不能变,可改变的是没有加入k点的i,j之间的最短路,设为dist[i,j]。那么最短环的长度表示为dist[i,j]+map[i,k]+map[k,j]。

    Floyd的最外层循环为k时,最短路还没有用k和更新ij之间的最短路,恰好符合要求。所以在还没有用k更新ij之间的最短路之前更新环,每次更新环时更新路径即可。

    算法步骤:

    输入输出Floyd算法的框架,三个循环,在更新路径前更新环的最短路径。题解一和其他的题解(都是DP)代码很短,步骤很清晰,所以算法步骤粗略写写。

    算法复杂度:

    输入输出两个循环不超过O(n2),时间主要消耗在Floyd算法的框架里,三个n次循环,所以时间复杂度O(n3),最多是二维数组,空间复杂度是O(n2)

    代码: 

     1 const int maxn=110; 
     2 int dist[maxn][maxn], map[maxn][maxn]; //最短距离,原图
     3 int pre[maxn][maxn]; // pre[i,j]记录最短路里,j前面一个点
     4 int path[maxn];      // 答案路径
     5 int n, m, num, minc; // num记录path里有多少个点,minc是最短环长度
     6  
     7 int main()
     8 {
     9     int  u, v, cost;
    10 while(cin >> n && n){ 
    11       if(n<0) break;
    12         cin >> m; 
    13         for(int i=1; i<=n; i++){
    14             for(int j=1; j<=n; j++){
    15                 dist[i][j]=map[i][j]=INF;
    16                 pre[i][j]=i;
    17             }
    18       }
    19       for(int i=1; i<=m; i++){
    20           scanf("%d %d %d",&u,&v,&cost);
    21           if(dist[u][v]>cost)   //重边
    22               map[u][v]=map[v][u]=dist[u][v]=dist[v][u]=cost;
    23       } 
    24     // floyd
    25     minc=INF;
    26 for(int k=1; k<=n; k++){
    27 // k还没加入(i,j)最短路,更新最短环
    28         for(int i=1; i<k; i++){
    29             for(int j=i+1; j<k; j++){
    30                 int  ans=dist[i][j]+map[i][k]+map[k][j];
    31                 if(ans<minc){  //找到最优解
    32                     minc=ans;
    33                     num=0;
    34                     int p=j;
    35                     while(p!=i){  //逆向寻找前驱遍历的路径并将其存储起来
    36                         path[num++]=p;
    37                         p=pre[i][p];
    38                     }
    39                     path[num++]=i;
    40                     path[num++]=k;
    41                 }
    42             }
    43         }
    44         //用k更新i到j的最短路径
    45         for(int i=1; i<=n; i++){
    46             for(int j=1; j<=n; j++){
    47                 if(dist[i][j]>dist[i][k]+dist[k][j]){
    48                     dist[i][j]=dist[i][k]+dist[k][j];
    49                     pre[i][j]=pre[k][j];
    50                 }
    51             }
    52         }
    53     }// end Floyd 
    54     if(minc==INF) puts("No solution.");
    55     else{
    56         printf("%d",path[0]);
    57         for(int i=1; i<num; i++)
    58             printf(" %d",path[i]);
    59         puts("");
    60      }
    61 }
    62    return 0;
    63 }
  • 相关阅读:
    数据库链接字符汇总
    CSS 继承深度解析
    autofac
    SmartStoreNet解图
    RPM ,DPKG ,YUM ,APT-GET
    ubuntu中查看各种设备和资源的命令汇总
    linux中一些常用的命令总结
    latex 插图排版
    matplotlib 出图示例
    latex 生成pdf
  • 原文地址:https://www.cnblogs.com/tinyork/p/5044046.html
Copyright © 2011-2022 走看看