码迷,mamicode.com
首页 > 编程语言 > 详细

Floyd-Warshall算法正确性证明

时间:2020-04-27 13:42:04      阅读:83      评论:0      收藏:0      [点我收藏+]

标签:扩展   line   mat   for   基于   ++   并且   其他   部分   

以下所有讨论,都是基于有向无负权回路的图上的。因为这一性质,任何最短路径都不会含有环,所以也不讨论路径中包含环的情形!并且为避免混淆,将“最短路径”称为权值最小的路径,将路径经过的点数-1称为路径的长度。

先列出算法的c语言代码实现,后面将用这段代码来辅助证明。

int n;//从1..n共n个点
int dis[maxn][maxn];//权值邻接矩阵
init();//初始化数据
for(int k=1;k<=n;++k)
    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]);

先用比较形象的语言来简单叙述一遍。

  • 以下“每次更新路径”指k=k_i时内层的两重循环,k是每次更新路径采用的“中间点”。
  • 每个点k在被用作中间点时,相关路径的最小权值,已经被继承到本次更新的路径里了。其他没有被更新的点想通过k进行连接,就一定包含本次更新的路径。并且后续只保留任意两个端点间权值最小的那条路径进行计算。
  • 因此在更新n次后,与所有点的相关路径的最小权值,都已经更新完毕。也就是说,所有的路径都已经考虑并更新过了。

下面是比较符号化的严谨证明。

  • 设共有\(1..n\)\(n\)个点,初始化所有长度为1的路径集合为\(R\)\(x\)\(y\)的当前最小路径权值为\(dis[x][y]\),这个最小权值对应\(R\)中的一条路径\(x,r_1,r_2,...,y\)
  • 现在采用数学归纳法,以\(k=1..n\)进行\(n\)次路径扩展,并更新\(R和dis[][]\)
  • \(k=1\)时,\(R\)中已经包含所有顶点两两连接的路径。选取所有的路径\(x,k和k,y\),进行连接得到\(G\{d|d=x,k,y\}\)\(R=R\cup G\),更新\(dis[][]\)
    这样,\(R\)中就包含了:起点与终点之间(不包含起点、终点),仅含点1的所有路径。因为没有负权回路,所以后续更新的多次经过点1的路径都不影响最小权值性质,并且也可以被R中去除路径中回路部分的路径替代(不影响其连接作用且权值更小,以下将不再讨论有回路的路径情况)。
  • 假设当\(k=1..n\)时,\(R\)中已经包含:起点与终点之间(不包含起点、终点),仅含\(1..k-1\)的所有路径。令\(r_k=k\),选取R中的所有起点为\(k\)的路径\(S\{d|d=x,r_1,r_2,...r_k\}\),和所有以\(k\)为终点的路径\(T\{d|d=r_k,r_k+1,...y\}\),让\(S\)\(T\)中的路径两两连接,得到\(G\{d|d=x,...,r_k,...,y\}\)。然后令\(R=R\cup G\),更新\(dis[][]\)。这样,\(R\)中就已经包含了:起点与终点之间(不包含起点、终点),仅含\(1..k\)的所有路径。原假设成立。
  • 上述做法进行到\(k=n\)结束,\(R\)中就已经包含了这个图所有的路径连接可能。而更新\(dis[][]\)的步骤,因为所有的\(R\)中的路径对应的\(dis[i][k]\)\(dis[k][j]\)都在之前计算过了,所以实际上每轮就只需计算\(dis[i][j]=min\{dis[i][j],dis[i][k]+dis[k][j]\}\)

在做作业的时候遇到这个算法,想起来好像一直在用但并不理解它的正确性,所以尝试证明了一下。正好也作为我写博客的一个开头吧。

Floyd-Warshall算法正确性证明

标签:扩展   line   mat   for   基于   ++   并且   其他   部分   

原文地址:https://www.cnblogs.com/crazyfz/p/12785136.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!