zoukankan      html  css  js  c++  java
  • 「LOJ#10072」「一本通 3.2 例 1」Sightseeing Trip(无向图最小环问题)(Floyd

    题目描述

    原题来自:CEOI 1999

    给定一张无向图,求图中一个至少包含 333 个点的环,环上的节点不重复,并且环上的边的长度之和最小。该问题称为无向图的最小环问题。在本题中,你需要输出最小环的方案,若最小环不唯一,输出任意一个均可。若无解,输出 No solution.。图的节点数不超过 100100100

    输入格式

    第一行两个正整数 n,mn,mn,m 表示点数和边数。
    接下来 mmm 行,每行三个正整数 x,y,zx,y,zx,y,z,表示节点 x,yx,yx,y 之间有一条长度为 zzz 的边。

    输出格式

    输出一个最小环的方案:按环上顺序输出最小环上的点。若最小环不唯一,输出任意一个均可。若无解,输出 No solution.

    样例

    样例输入

    5 7
    1 4 1
    1 3 300
    3 1 10
    1 2 16
    2 3 100
    2 5 15
    5 3 20

    样例输出

    1 3 5 2

    题解

    无向图的最小环问题啊,不知道在多少场考试中间卡住了我的临门一脚。——hzz

    教材:http://www.cnblogs.com/Yz81128/archive/2012/08/15/2640940.html#undefined

    这个最小环中,一定会有一个编号最大的点。

    那么我们设$dp[i][j][k]$为在只经过$1$~$k$的点时,$i$,$j$的最短距离。

    那么如果我们设最小环中最大的点为$k$,它两边有点$i$,$j$,

    那么答案的最小值就是$dp[i][j][k-1]+g[j][k]+g[k][i]$。

    //

    然后我们联想Floyd的过程,

    $for$ $int$ $k=1$ $to$ $n$

        $for$ $int$ $i=1$ $to$ $n$

      $for$ $int$ $j=1$ $to$ $n$

    也就是说,在$k$时,$i$,$j$的最小值都只中转了$1$~$k$的点。

    这不就是我们要的$dp[i][j][k]$嘛?!

    于是我们可以在Floyd的同时顺便维护答案。

    并且$dp$数组的$k$那一维还是可以省掉的。

    //详见代码吧qwq

     1 编号    题目    状态    分数    总时间    内存    代码 / 答案文件    提交者    提交时间
     2 #239580    #10072. 「一本通 3.21」Sightseeing Trip Accepted    100    45 ms    380 KiB    C++ / 1.2 K    qwerta    2018-10-22 16:48:53
     3 
     4 #include<iostream>
     5 #include<cstring>
     6 #include<cstdio>
     7 #include<cmath>
     8 using namespace std;
     9 #define LL long long 
    10 int g[103][103];//直接连边的距离
    11 int dis[103][103];//有中转点的距离
    12 int q[103];
    13 int toq=0;
    14 int zz[103][103];//zz[i][j]表示从i到j的最小路径的中转点
    15 void getpath(int u,int v)
    16 {
    17     if(!zz[u][v])return;
    18     getpath(u,zz[u][v]);//从u往中转点找
    19     q[++toq]=zz[u][v];
    20     getpath(zz[u][v],v);
    21     return;
    22 }
    23 int main()
    24 {
    25     //freopen("a.in","r",stdin);
    26     int n,m;
    27     scanf("%d%d",&n,&m);
    28     memset(g,127,sizeof(g));
    29     for(int i=1;i<=n;++i)
    30       g[i][i]=0;
    31     for(int i=1;i<=m;++i)
    32     {
    33         int x,y,l;
    34         scanf("%d%d%d",&x,&y,&l);
    35         g[x][y]=min(g[x][y],l);
    36         g[y][x]=g[x][y];
    37     }
    38     memcpy(dis,g,sizeof(g));
    39     long long ans=1e9+7;
    40     for(int k=1;k<=n;++k)
    41     {
    42         for(int i=1;i<k;++i)
    43         for(int j=i+1;j<k;++j)//因为k为环内最大点,所以只能循环到k-1
    44         {
    45             if(1LL*dis[i][j]+g[j][k]+g[k][i]<ans)
    46             {
    47                 ans=dis[i][j]+g[j][k]+g[k][i];
    48                 toq=0;
    49                 q[++toq]=i;
    50                 getpath(i,j);
    51                 q[++toq]=j;
    52                 q[++toq]=k;
    53             }
    54         }
    55         //然后是正常Floyd
    56         for(int i=1;i<=n;++i)
    57         for(int j=1;j<=n;++j)
    58         {
    59             if(1LL*dis[i][k]+dis[k][j]<dis[i][j])
    60             {
    61                 dis[i][j]=dis[i][k]+dis[k][j];
    62                 zz[i][j]=k;
    63             }
    64         }
    65     }
    66     if(!toq){cout<<"No solution.";return 0;}
    67     for(int i=1;i<=toq;++i)
    68       cout<<q[i]<<" ";
    69     return 0;
    70 }
  • 相关阅读:
    动态规划精讲(一)LC最长公共子序列
    0-1背包
    折线分割平面
    母牛的故事
    数塔
    70. 爬楼梯
    文件修改的两种方式
    文件处理练习
    文件处理
    购物车理解
  • 原文地址:https://www.cnblogs.com/qwerta/p/9833391.html
Copyright © 2011-2022 走看看