• vijosP1046 观光旅游(最小环)


    vijosP1046 观光旅游

    链接:https://vijos.org/p/1046

    【思路】

      Floyd求解最小环。

    【代码】 

     1 #include<iostream>
     2 using namespace std;
     3 
     4 const int maxn = 100+10;
     5 const int INF=1e8;
     6 int f[maxn][maxn],dist[maxn][maxn];
     7 int n,m,min_loop;
     8 
     9 void Floyd() 
    10 {
    11     min_loop=INF;
    12     for(int k=1;k<=n;k++) 
    13     {
    14         for(int i=1;i<k;i++)
    15            for(int j=i+1;j<k;j++)
    16               if(f[i][j]+dist[i][k]+dist[k][j]<min_loop)
    17                  min_loop=f[i][j]+dist[i][k]+dist[k][j];
    18         
    19         for(int i=1;i<=n;i++)
    20            for(int j=1;j<=n;j++)
    21               if(f[i][k]<INF && f[k][j]<INF)
    22                  f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
    23     }
    24 }
    25 
    26 int main() {
    27     ios::sync_with_stdio(false);
    28     while(cin>>n>>m)
    29     {
    30         for(int i=1;i<=n;i++)
    31          {
    32            f[i][i]=dist[i][i]=0;
    33            for(int j=i+1;j<=n;j++) 
    34               f[i][j]=f[j][i]=dist[i][j]=dist[j][i]=INF;
    35         }
    36         int u,v,w;
    37         for(int i=0;i<m;i++) {
    38             cin>>u>>v>>w;
    39             dist[u][v]=dist[v][u]=f[u][v]=f[v][u]=w;
    40         }
    41         Floyd();
    42         if(min_loop==INF) cout<<"No solution.
    ";
    43         else cout<<min_loop<<"
    ";
    44     }
    45     return 0;
    46 }
    View Code

    【参考代码及原理】

      1 /*
      2  *算法引入:
      3  *求一个图G中的最小环路的朴素算法为:每次找到一条边,删除了求这两点之间的最短路径;
      4  *若能求出,则这条最短路径与原来的边构成一个环,不过时间复杂度略高;
      5  *
      6  *算法思想;
      7  *Floyd算法是按照顶点的编号增加的顺序更新最短路径的;
      8  *如果存在最小环,则会在这个环中的点编号最大的那个点u更新最短路径之前发现这个环;
      9  *即当点u被拿来更新i到j的最短路径的时候,可以发现这个闭合环路;
     10  *发现的方法是,更新最短路径前,遍历i,j点对,一定会发现某对i到j的最短路径长度:
     11  *dist[i][j]+map[j][u]+map[u][i]!=INF,这时s的i和j是当前环中挨着点u的两个点;
     12  *因为在之前的最短路径更新过程中,u没有参与更新,所以dist[i][j]所表示的路径中不会有点u,即一定为一个环;
     13  *
     14  *如果在每个新的点拿来更新最短路径之前遍历i和j验证上面的式子,虽然不能遍历到所有的环;
     15  *但是由于dist[i][j]是i到j点的最短路径m所以肯定可以遍历到最小的环;
     16  *
     17  *如果有负权环,则该算法失效,因为包含负环的图上,dist[i][j]已经不能保证i到j的路径上不会经过同一个点多次了;
     18  *
     19  *算法测试:
     20  *PKU1734(Sightseeing trip)
     21  */
     22 
     23 #include<iostream>
     24 #include<cstring>
     25 #include<cstdlib>
     26 #include<queue>
     27 #include<cstdio>
     28 #include<climits>
     29 #include<algorithm>
     30 using namespace std;
     31 
     32 const int N=111;
     33 const int INF=0xffffff;
     34 
     35 int min_loop;
     36 int num;
     37 int map[N][N],dist[N][N],pre[N][N];
     38 int path[N];
     39 int n,m;
     40 
     41 void dfs(int i,int j)
     42 {
     43     int k=pre[i][j];
     44     if(k==0)
     45     {
     46         path[num++]=j;
     47         return;
     48     }
     49     dfs(i,k);
     50     dfs(k,j);
     51 }
     52 
     53 void Floyd()
     54 {
     55     min_loop=INF;
     56     memset(pre,0,sizeof(pre));
     57     for(int k=1; k<=n; k++)
     58     {
     59         for(int i=1; i<k; i++)   //i<k
     60         {
     61             for(int j=i+1; j<k; j++)    //j<k 
     62             {
     63                 if(dist[i][j]+map[i][k]+map[k][j]<min_loop)
     64                 {
     65                     min_loop=dist[i][j]+map[i][k]+map[k][j];
     66                     num=0;
     67                     path[num++]=i;
     68                     dfs(i,j);
     69                     path[num++]=k;
     70                 }
     71             }
     72         }
     73 
     74         for(int i=1; i<=n; i++)
     75         {
     76             for(int j=1; j<=n; j++)
     77             {
     78                 if(dist[i][k]+dist[k][j]<dist[i][j])
     79                 {
     80                     dist[i][j]=dist[i][k]+dist[k][j];
     81                     pre[i][j]=k;
     82                 }
     83             }
     84         }
     85     }
     86 }
     87 
     88 int main()
     89 {
     90    // freopen("C:\Users\Administrator\Desktop\kd.txt","r",stdin);
     91     while(~scanf("%d%d",&n,&m))
     92     {
     93         for(int i=1; i<=n; i++)
     94         {
     95             for(int j=i+1; j<=n; j++)
     96                 map[i][j]=map[j][i]=dist[i][j]=dist[j][i]=INF;
     97             map[i][i]=dist[i][i]=0;
     98         }
     99         for(int i=0; i<m; i++)
    100         {
    101             int u,v,w;
    102             scanf("%d%d%d",&u,&v,&w);
    103             if(w<map[u][v])
    104             {
    105                 map[u][v]=map[v][u]=w;
    106                 dist[u][v]=dist[v][u]=w;
    107             }
    108         }
    109         Floyd();
    110         if(min_loop==INF)
    111             puts("No solution.");
    112         else
    113         {
    114             for(int i=0; i<num-1; i++)
    115                 printf("%d ",path[i]);
    116             printf("%d
    ",path[num-1]);
    117         }
    118     }
    119     return 0;
    120 }

      转载地址:http://blog.csdn.net/jarily/article/details/8872487

  • 相关阅读:
    c++重点笔记2
    c++学习笔记重点1
    创业思路(3) 传统行业与互联网思维
    创业思路(2) 社交
    创业思路(1)
    Asp.Net实现Http长连接推送
    又回来了
    2021.10.23软件更新公告
    2021.10.22软件更新公告
    SharePoint 2013 新特性 (三) 破改式 —— 设计管理器的使用 [2.HTML变身模板页]
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4911241.html
Copyright © 2020-2023  润新知