Floyd算法及其应用

Part I-Introduction

Floyd算法是一种求图上多源最短路径的算法,适用于中小规模的图,思维简单易懂。

Floyd算法的实质是(区间)动态规划,在这里做一个简单的概述。

对于一个有\(n\)个结点的图,

\(dis[i][j]\)为结点\(i\)到结点\(j\)的最短路径长度。

首先,将所有现成的边都存入\(dis\),其余的令其值\(=\infty\),并使\(dis[i][i]=0\)

接着,枚举中转点(\(k\)),那么:

\[dis[i][j]=\min\{dis[i][k]+dis[k][j]\text{ | }k\in[1,n],k\ne i,k\ne j\}\]

代码实现:

void Floyd()
{memset(dis,0x3f3f3f3f,sizeof(dis));for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(a[i][j]!=0x3f3f3f3f)边(i,j)存在。dis[i][j]=a[i][j];//a为现存的边。for(int i=1;i<=n;i++) dis[i][i]=0;for(int k=1;k<=n;k++)//枚举中转点。for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){if(i==j||j==k||k==i) continue;dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);}
}

Attention:循环时\(k\)必须放在第一层。若将\(i\)置于第一层,就会导致i->k->j的距离过早的确定下来,可能会导致答案错误。

注:其实最原始的Floyd中\(dis\)的定义是:\(dis[i][j][k]\)表示结点\(i\)到结点\(j\)只经过结点\(i-k\)的最短路径。 则有:\(dis[i][j][k]=min(dis[i][j][k-1],dis[i][k][k-1]+dis[k][j][k-1])\),降维得到现在的方程。

时间复杂度:\(O(n^3)\)

Part II-Sevral Simple Problems

Floyd算法可以解决许多看似无法处理的问题。

Problem[1]:[USACO09JAN] Best Spot

链接:https://www.luogu.org/problemnew/show/P2935

题面:

ZgPxGd.png

此题较为简单,算法流程:

  • Floyd处理出各个点间的最短路径。

  • 计算出每个点到各个Favorites的总距离。

  • 选出总距离最小的点输出即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define R registerint a[501][501];
int dis[501][501];
int fav[501];
int P,F,C;void Floyd()
{memset(dis,0x3f3f3f3f,sizeof(dis));for(R int i=1;i<=P;i++)for(R int j=1;j<=P;j++)if(a[i][j]!=0x3f3f3f3f)dis[i][j]=a[i][j];for(R int i=1;i<=P;i++) dis[i][i]=0;for(R int k=1;k<=P;k++)for(R int i=1;i<=P;i++)for(R int j=1;j<=P;j++){if(i==j||j==k||k==i) continue;dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);}
}signed main()
{scanf("%d%d%d",&P,&F,&C);memset(a,0x3f3f3f3f,sizeof(a));for(R int i=1;i<=F;i++) scanf("%d",fav+i);for(R int u,v,w,i=1;i<=C;i++){scanf("%d%d%d",&u,&v,&w);a[u][v]=a[v][u]=min(a[u][v],w);}Floyd();int minnum=0x3f3f3f3f,minid;for(R int i=1,sum=0;i<=P;i++,sum=0){for(R int j=1;j<=F;j++)sum+=dis[i][fav[j]];if(sum<minnum) minnum=sum,minid=i;}printf("%d\n",minid);return 0;} 

Problem[2]:[JSOI2007]重要的城市

链接:https://www.luogu.org/problemnew/show/P1841

题面:

Zg85Js.png

这一题比上一题略难,如何记录中转点?

Of course,在Floyd的时候。

\(c[i][j]\)为结点\(i,j\)之间的最短路的中转点,若无则为0;

在进行对\(dis[i][j]\)的更新之时,我们不直接取min,而是先判断以避免覆盖。

因为我们还要进行一个更重要的操作,that is,更新\(c[i][j]\)

分情况讨论:

  • 1.\(dis[i][j]>dis[i][k]+dis[k][j]\)(需要更新):此时结点\(i,j\)之间的最短路的中转点就要发生改变,即\(c[i][j]=k\),并更新\(dis[i][j]\)的值。

  • 2.\(dis[i][j]=dis[i][k]+dis[k][j]\) :这不仅说明原先的\(c[i][j]\)已经失效,而且意味着此时已经不存在\(c[i][j]\)了(并不需要中转点就有最短路了)。因此令\(c[i][j]=0\)

  • 3.\(dis[i][j]<dis[i][k]+dis[k][j]\):此时的中转点无法得到更优的解,忽略。

这样我们就处理好了\(c\)。对于结果的处理,可以利用桶排序的思想,令\(res[c[i][j]]=1\)。(res[N]:bool)

最后遍历\(res\),输出答案(别忘了无解的处理!!!)。

#include<cstdio>
#include<bitset>
#include<cstring>
using namespace std;const int N=205;
int c[N][N];
int f[N][N];
int n,m;void Solve()
{for(int i=1;i<=n;i++) f[i][i]=0;for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){if(i==j||j==k||i==k) continue;if(f[i][j]>f[i][k]+f[k][j])f[i][j]=f[i][k]+f[k][j],c[i][j]=k;else if(f[i][j]==f[i][k]+f[k][j])c[i][j]=0;}
}bool res[N],flag=0;
signed main()
{memset(f,0x3f3f3f3f,sizeof(f));memset(c,0,sizeof(c));scanf("%d%d",&n,&m);for(int u,v,w,i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);f[u][v]=f[v][u]=w;//f:=dis}Solve();for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)res[c[i][j]]=1;for(int i=1;i<=n;i++)if(res[i]) printf("%d ",i),flag=1;if(!flag) puts("No important cities.");return 0;
}

Problem[3]:[NOI2007]社交网络

链接:https://www.luogu.org/problemnew/show/P2047

题面:

ZgJVBT.png

这题貌似比上一题更复杂——要进行路径计数。

\(cnt[i][j]\)为结点\(i,j\)之间的最短路径条数

还是在处理\(dis\)的时候处理\(cnt\)

分类讨论之前,你需要知道一件事情:

假设我们已经处理完了\(cnt[i][k]\)\(cnt[k][j]\),那么怎么知道\(cnt[i][j]\)的值? 对于\(cnt[i][k]\)中的每条路径,与\(cnt[k][j]\)配对,有\(cnt[k][j]\)条路径。 那么\(cnt[i][k]\)条一起配对就是\(cnt[i][k]\times cnt[k][j]\)条,这就是\(cnt[i][j]\)的值。(说白了就是乘法原理)

那么,再开始分类讨论

  • 1.\(dis[i][j]=dis[i][k]+dis[k][j]\):又找到了一坨解,\(cnt[i][j]+=cnt[i][k]*cnt[k][j]\)(注意是+=!)。

  • 2.\(dis[i][j]>dis[i][k]+dis[k][j]\) :这代表有了新的解,原先的答案不能再用了,\(cnt[i][j]=cnt[i][k]*cnt[k][j]\)(注意是=!)。

  • 3.\(dis[i][j]<dis[i][k]+dis[k][j]\):此时的中转点无法得到更优的解,忽略。

处理完\(cnt\)后,那就意味着\(C_{s,t},C_{s,t}(v)\)什么的都出来了。

P.S.:建议cnt用double

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;const int N=105;
int dis[N][N];
double cnt[N][N];
int n,m;signed main()
{memset(dis,0x3f3f3f3f,sizeof(dis));memset(cnt,0,sizeof(cnt));scanf("%d%d",&n,&m);for(int u,v,w,i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);dis[u][v]=dis[v][u]=min(w,dis[u][v]);cnt[u][v]=cnt[v][u]=1;}for(int i=1;i<=n;i++)dis[i][i]=0;for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){if(i==j||i==k||j==k) continue;if(dis[i][j]==dis[i][k]+dis[k][j])cnt[i][j]+=cnt[i][k]*cnt[k][j];else if(dis[i][j]>dis[i][k]+dis[k][j]){dis[i][j]=dis[i][k]+dis[k][j];cnt[i][j]=cnt[i][k]*cnt[k][j];}}for(int k=1;k<=n;k++){double ans=0;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){if(i==j||i==k||j==k) continue;if(dis[i][j]==dis[i][k]+dis[k][j])ans+=cnt[i][k]*cnt[k][j]*1.0/cnt[i][j];}printf("%.3lf\n",ans);}
}

Part III-EXT:最小环问题

来看这么一个问题:http://acm.hdu.edu.cn/showproblem.php?pid=1599

题面:

Z2P9oD.png

看似无从下手,但仍然是Floyd

在更新\(dis\)前,我们已经把\(1-(k-1)\)的情况处理好了。那么当前的最小环就是:

\[\min\{a[i][k]+a[k][j]+dis[i][j]\}\]

先贴代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;const int N=105;
int a[N][N];
int dis[N][N];
int n,m;long long solve()
{long long min_circle=0x3f3f3f3f;for(int k=1;k<=n;k++){for(int i=1;i<k;i++)for(int j=i+1;j<k;j++)min_circle=min(min_circle,1ll*a[i][k]+a[k][j]+dis[i][j]);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);}return min_circle;
}signed main()
{while(scanf("%d%d",&n,&m)!=EOF){memset(a,0x3f3f3f3f,sizeof(a));for(int u,v,w,i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);a[u][v]=a[v][u]=min(a[u][v],w);}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dis[i][j]=a[i][j];long long res=solve();if(res!=0x3f3f3f3f) printf("%lld\n",res);else puts("It's impossible.");}return 0;
}

值得注意的是,\(i,j\)的循环范围的控制,因为\(i,j,k\)不能相同。

至于为什么先处理最小环在更新路径,当然是为了使\(dis[i][j]\)不经过\(k\)啊。

转载于:https://www.cnblogs.com/-Wallace-/p/11165803.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件设计师--最早开始时间和最晚开始时间

题目如图所示&#xff0c;解法如下&#xff1a; 方法&#xff1a; 先求最早开始时间&#xff1a;A是开始节点&#xff0c;所以A的最早开始时间是0&#xff0c;并且最早开始时间等于最晚开始时间。等得到图中红色的部分。 其他节点的最早开始时间为以该节点作为弧头的所有有向…

软件设计师 --哈夫曼树的一个经典问题

题目如下&#xff1a;有很多人反应&#xff0c;他们怎么做都做不出正确的答案&#xff0c;结果发过他们画的哈夫曼树的图以后&#xff0c;发现图完全是错误的&#xff1b; 如下图所示&#xff1a;为什么错误的&#xff0c;因为在遇到有两个权重为17的树的时候&#xff0c;没有遵…

mini2440烧写nor flash

1. 安装Setup_JLinkARM_V440.exe 2. 打开JLINK ARM 3. File->Open Project&#xff0c;打开 s3c2440a_embedclub.jflash4. Options->Project settings... 选择 Flash&#xff0c;点击 Select flash device&#xff0c;选中开发板对应的 Nor Flash 芯片型号。比 如 S29AL0…

软件设计师--判定覆盖,判定条件覆盖,条件组合覆盖--一个栗子

针对上图的一个判断条件&#xff0c;在这里将分别讨论判定覆盖、判定条件覆盖、条件组合覆盖的情况&#xff1a; 设T1A>3,T2B>3;为该判定节点的两个子条件。 (一&#xff09;判定覆盖&#xff1a; 所谓的判定覆盖就是让判定的真分支和假分支各执行一次&#xff0c;只要…

python3 多继承搜索__init__方法的两种策略

继承情形一&#xff1a;测试代码如下&#xff1a; class A(object):def __init__(self):print(A)class B(object):def __init__(self):print(B)class C(A):def __init__(self):print(C)class D(B): def __init__(self):print(D)class E(C, D):pass执行当前代码 xE()&#xff0c…

Unity Shader 屏幕后效果——Bloom外发光

Bloom的原理很简单&#xff0c;主要是提取渲染图像中的亮部区域&#xff0c;并对亮部区域进行模糊处理&#xff0c;再与原始图像混合而成。 一般对亮部进行模糊处理的部分采用高斯模糊&#xff0c;关于高斯模糊&#xff0c;详见之前的另一篇博客&#xff1a; https://www.cnblo…

不要假装努力,结果不会陪你演戏!

转载于:https://www.cnblogs.com/strive-19970713/p/11171205.html

机器学习基石-作业二-第10题分析

题目如上图所示&#xff0c;答案是&#xff1a;&#xff1b;在网上看到的答案中有一个很好的解释就是说在一个n纬的欧几里德空间里&#xff0c;分别按照参数做一个垂直于每个轴的超平面&#xff0c;这些超平面能够打散这么多个点。首先我承认这个事实&#xff0c;具体的证明还没…

机器学习基石作业二中的DECISION_STUMP实现

概要&#xff1a;在林老的题目描述中&#xff0c;DECISION_STUMP&#xff08;其实就是“决策桩”&#xff0c;也就是只有一层的决策树&#xff09;。题目中提到了的选去是把属性&#xff08;一维的&#xff09;按照从小到大的顺序排列以后取两个挨着的值的平均值&#xff0c;网…

【MM系列】SAP 关于更改物料的价格控制类型

公众号&#xff1a;SAP Technical本文作者&#xff1a;matinal原文出处&#xff1a;http://www.cnblogs.com/SAPmatinal/ 原文链接&#xff1a;【MM系列】SAP 关于更改物料的价格控制类型前言部分 大家可以关注我的公众号&#xff0c;公众号里的排版更好&#xff0c;阅读更舒适…

机器学习基石-作业三-第2题分析以及通过H证明EIN的讨论

题目&#xff1a; 这是机器学习基石作业三种的第二小题&#xff0c;额&#xff0c;在网上看了很多解答&#xff08;解答也不多&#xff09;感觉都没有说清楚为什么&#xff0c;所以励志清楚滴解决一下这个问题&#xff0c;经过努力&#xff0c;自认为得到了详细的解答&#xff…

Nginx的平滑升级记录---适用于编译安装的Nginx

一、查看自己的Nginx的版本号 [rootlocalhost sbin]# cd /usr/local/nginx/sbin/ [rootlocalhost sbin]# ls nginx [rootlocalhost sbin]# ./nginx -V nginx version: nginx/1.15.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) configure arguments: 二、确定自己要…

02(c)多元无约束优化问题-牛顿法

此部分内容接《02(a)多元无约束优化问题》&#xff01; 第二类&#xff1a;牛顿法(Newton method) \[f({{\mathbf{x}}_{k}}\mathbf{\delta })\text{ }\approx \text{ }f({{\mathbf{x}}_{k}}){{\nabla }^{T}}f({{\mathbf{x}}_{k}})\cdot \mathbf{\delta }\frac{1}{2}{{\mathbf{\…

推荐系统浅浅的例子

对于推荐系统&#xff0c;有很多的很强大的算法。这里作为练习&#xff0c;只介绍基本的协同过滤算法&#xff08;userbased&#xff09;和FM&#xff08;通过梯度下降的角度&#xff0c;还可以通过交替优化的角度来看&#xff09;。 这里的例子是在七月算法的视频中看的&#…

TPL Dataflow .Net 数据流组件,了解一下?

回顾上文 作为单体程序&#xff0c;依赖的第三方服务虽不多&#xff0c;但是2C的程序还是有不少内容可讲&#xff1b; 作为一个常规互联网系统&#xff0c;无外乎就是接受请求、处理请求&#xff0c;输出响应。 由于业务渐渐增长&#xff0c;数据处理的过程会越来越复杂和冗长&…

推荐系统实例

协同过滤与隐语义模型 在机器学习问题中&#xff0c;我们见到的数据集通常是如下的格式&#xff1a; input target ... ... &#xff0c;一个输入向量的集合以及对应的数据集合,就是我们想要去预测的值。 对于…

【转】深入理解JavaScript闭包(closure)

文章来源&#xff1a;http://www.felixwoo.com/archives/247 最近在网上查阅了不少Javascript闭包(closure)相关的资料&#xff0c;写的大多是非常的学术和专业。对于初学者来说别说理解闭包了&#xff0c;就连文字叙述都很难看懂。撰写此文的目的就是用最通俗的文字揭开Java…

从头开始建立神经网络翻译及扩展

目录翻译从头开始建立神经网络-简介导包和配置生成一个数据集实现用来展示决策边界的辅助函数Logistic Regression训练一个神经网络我们的神经网络如何进行预测学习神经网络的参数实现神经网络训练一个隐层有3个神经元的神经网络验证隐层神经元个数对神经网络的影响练习练习题解…