热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2020.08.23日常总结:探讨无向图的最小环问题及Floyd算法的本质

[Problem]\color{green}{\texttt{[Problem]}}[Problem]给定一个nnn个点mmm条边的无向图,求出一个至少有333个点的环,使得环上的

[Problem]\color{green}{\texttt{[Problem]}}



  • 给定一个 nn 个点 mm 条边的无向图,求出一个至少33 个点的环,使得环上的边的边权的总和最小。无解就输出 No solution.(注意,. 是必须的)。

  • 1n100,1m5×1031 \leq n \leq 100,1 \leq m \leq 5 \times 10^3

  • dd 为边权的最大值,则有 1d1×1051\leq d \leq 1 \times 10^5


[Solution]\color{green}{\texttt{[Solution]}}

[Part one]\color{blue}{\texttt{[Part one]}} Floyd 的本质是什么?

对于很多人(包括一年前的笔者)而言,Floyd 算法就是:

for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

这样一个 O(n3)O\left (n^3\right) 的多源最短路算法而已。

但是为什么 Floyd 算法是对的呢?这就涉及它的核心。

原始的 Floyd 是这样的:记 fk,i,jf_{k,i,j} 表示从 iijj 且只使用 1k1-k 号节点作为中转点的最短路长度。什么是中转点,就是最短路径 (i,j)(i,j) 上除了 iijj 的那些点。

于是我们有如下的转移方程:

fk,i,j=min1lk1{fk1,i,k+fk1,k,j}f_{k,i,j}=\min\limits_{1 \leq l \leq k-1}\left \{f_{k-1,i,k}+f_{k-1,k,j}\right \}

它的意义是先只用 11ll 号节点做中转点从 ii 走到 kk,再只用 11ll 号节点做中转点从 kk 走到 jj

于是我们可以用滚动数组优化它,就得到了我们上面的代码(顺便一提,正是因为我们用了滚动数组,所以 kk 才要在最外层)。

[Part two]\color{blue}{\texttt{[Part two]}} 回归原题

讲了这么多,它和原题有什么关系呢?

我们假设这个环上有一条边 (i,j)(i,j),去除这条边后,剩下的一定是从 iijj 的最短路,如图:

在这里插入图片描述

有什么用?我们随便找两个点 iijj,求出它们在只使用 11k1k-1 号点作为中转点时的最短路 Ti,j,k1T_{i,j,k-1}ff 实在出现了太多次了,所以为了让读者明白究竟方式了什么,这里换一个字母),连接点 iikk,在连接点 kkjj,就可以得到一个环。

所以,最小的环的权值(就是换上所有边的权值总和)ans\texttt{ans} 的推导式为:

ans=mini,j,k{1..n}{Tk1,i,j+ai,k+ak,j}\texttt{ans}=\min\limits_{i,j,k \in \left \{ 1..n \right \} } \left \{ T_{k-1,i,j}+a_{i,k}+a_{k,j} \right \}

ai,ja_{i,j} 表示边 (i,j)(i,j) 的权值(长度)。

注意,图上必须要有边 (i,k)(i,k) 和边 (k,j)(k,j) 才可以。

[code]\color{blue}{\texttt{[code]}}

typedef long long ll;
const ll inf=0x3f3f3f3f3f3f;
ll a[110][110],f[110][110],n,m,ans;
inline void ckmin(ll &a,ll b){a=min(a,b);//让a取到a,b间较小值
}
int main(){scanf("%lld%lld",&n,&m);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j]=a[i][j]=inf;for(int i=1,u,v,w;i<=m;i++){scanf("%d%d%d",&u,&v,&w);ckmin(a[u][v],w);ckmin(a[v][u],w);ckmin(f[u][v],w);ckmin(f[v][u],w);}ans=inf;//求最小,初始极大 for(int k=1;k<=n;k++){for(int i=1;i<k;i++)for(int j=i+1;j<k;j++)ckmin(ans,f[i][j]+a[i][k]+a[k][j]);for(int i=1;i<=n;i++)if (i!=k&&f[i][k]!=inf)for(int j=1;j<=n;j++)if (j!=i&&j!=k&&f[k][j]!=inf)ckmin(f[i][j],f[i][k]+f[k][j]);}if (ans!=inf) printf("%lld",ans);else printf("No solution.");return 0;
}洛谷的P6175就是模板哦。

推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 判断数组是否全为0_连续子数组的最大和的解题思路及代码方法一_动态规划
    本文介绍了判断数组是否全为0以及求解连续子数组的最大和的解题思路及代码方法一,即动态规划。通过动态规划的方法,可以找出连续子数组的最大和,具体思路是尽量选择正数的部分,遇到负数则不选择进去,遇到正数则保留并继续考察。本文给出了状态定义和状态转移方程,并提供了具体的代码实现。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
author-avatar
mobiledu2502917797
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有