任意两点间的最短路 Floyd及其本质

我们知道在已知起点的情况下,求到其他任何一点的最短路是用dijkstra,那么在一个有向图中,我们想知道任意两点之间的最短路,我们就可以使用floyd,而且这个算法表面看起来非常的简单,就是一个三重循环,如果这个图有N个点,那么复杂度为O(|N|3),代码如下。

1 for(int k=0;k<n;k++)
2 for(int i=0;i<n;i++)
3 for(int j=0;j<n;j++)
4 d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

在复杂度这么高的情况下,一般情况下如果不是板子题直接用的话肯定是会超时的,所以我们还是需要了解Floyd是怎么进行的,其实它的本质就是dp。

其实我从上面的代码中不难看出Floyd是采用状态转移的方式来更新各个点之间的距离的,而这个点就是k,即从i-j之间的最短路是否经过k点,不断的更新从而取得最优解,下面我们详细的说一下。

假设从顶点i出发,仅经由顶点Vk={1,2,3,···,k}抵达顶点j的最短路径成本为Ak[i,j]。首先,A0[i,j]表示从i到j不经由其他任何顶点,所以其值就等于连接i,j边的权值,如果不存在边时其大小为正无穷,接下来是k=1,2,3,···,|N|的情况,我们需要通过Ak-1来计算Ak,那么我们只需要考虑是否经过k点两种情况。

如果经过k,则路径会被分为i-k,k-j两个路径,而且这两个路径全都只经过Vk-1,中的顶点,因此Ak=Ak-1[i,k]+Ak-1[k,j]。

如果不经过k,那就意味着Ak[i,j]只经过i,j及属于Vk-1中的顶点,所以Ak[i,j]=Ak-1[i,j];

综上所知Ak[i,j]=min(Ak-1[i,j],Ak-1[i,k]+Ak-1[k,j])。

那么我们接下来看这个题目

洛谷P1119灾后重建

在这个题目中,图的状态是随着时间而改变的,在不同的时刻的询问下,任意两点之间的最短路也会发生改变,如果每问一次就用一次Floyd的话,毫无疑问的超时,那我们注意观察题目可以发现,某一个点能不能使用是随着时间变化的,我们在前面提到过,Floyd使用的点是根据k来变化的,及循环内部是用不到k+1及以后的点的,那么因为它的询问根据之间逐渐增加的,所以我们只要根据时间来不断的从更新k内部的点即可。

下面是完整代码

 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <algorithm>
 5 #include <queue>
 6 #include <stack>
 7 #include <stdio.h>
 8 #include <cmath>
 9 #include <string.h>
10
11 using namespace std;
12 #define ll long long
13 static const int WHITE=0;
14 static const int GRAY=1;
15 static const int BLACK=2;
16 static const int INF=(1<<20);
17 int N,M,Q;
18 int time1[205];
19 int map[205][205];
20 void floyd(int k)
21 {
22     for(int i=0;i<N;i++)
23     for(int j=0;j<N;j++)
24     map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
25     return ;
26 }
27 int main()
28 {
29     freopen("C:\\Users\\16599\\Desktop\\in.txt","r",stdin);
30     scanf("%d%d",&N,&M);
31     int now=0;
32     for(int i=0;i<N;i++)
33     {
34         int a;
35         scanf("%d",&a);
36         time1[i]=a;
37     }
38     for(int i=0;i<=N;i++)
39     for(int j=0;j<=N;j++)
40     map[i][j]=((i==j)?0:INF);
41     for(int m=0;m<M;m++)
42     {
43         int i,j,k;
44         scanf("%d%d%d",&i,&j,&k);
45         map[i][j]=map[j][i]=k;
46     }
47     scanf("%d",&Q);
48     for(int q=1;q<=Q;q++)
49     {
50         int x,y,t;
51         scanf("%d%d%d",&x,&y,&t);
52         while(time1[now]<=t&&now<=N)
53         {
54             floyd(now);
55             now++;
56         }
57         if(t<time1[x]||t<time1[y]||map[x][y]==INF)
58         printf("-1\n");
59         else
60         {
61             printf("%d\n",map[x][y]);
62         }
63     }
64     return 0;
65 }

原文地址:https://www.cnblogs.com/zlhdbk/p/11510840.html

时间: 2024-10-13 03:18:30

任意两点间的最短路 Floyd及其本质的相关文章

Floyd-Warshall算法(求解任意两点间的最短路) 详解 + 变形 之 poj 2253 Frogger

/* 好久没有做有关图论的题了,复习一下. --------------------------------------------------------- 任意两点间的最短路(Floyd-Warshall算法) 动态规划: dp[k][i][j] := 节点i可以通过编号1,2...k的节点到达j节点的最短路径. 使用1,2...k的节点,可以分为以下两种情况来讨论: (1)i到j的最短路正好经过节点k一次 dp[k-1][i][k] + dp[k-1][k][j] (2)i到j的最短路完全

AOJ -0189 Convenient Location (任意两点间的最短路)

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=78207 看懂题就好. 求某一办公室到其他办公室的最短距离. 多组输入,n表示n条关系,下面n次每次输入 x y d表示x到y的距离是d. 输出办公室的编号和距离. 因为 顶点数小于10,直接floyed求出所有距离之后,枚举出最短距离即可. 1 /* *********************************************** 2 Author : zch

图论之最短路02-1——任意两点间最短距离及路径

======================================================== 求任意两点间最短距离及其路径.(万能最短路) 输入:权值矩阵,起点,终点 输出:最短距离矩阵,指定起讫点路径(经过的顶点编号) 为任意一点到其他点最短路奠定基础 ======================================================== function [P d]=liangdianzuiduanlu(W,qidian,zhongdian) W

图论之最短路02-2——改进的任意两点间最短距离及路径

======================================================== 重要程度 ***** 求任意两点间最短距离及其路径.(万能最短路) 输入:权值矩阵,起点,终点 输出:最短距离矩阵,指定起讫点路径(经过的顶点编号) ======================================================== function renyizuiduanlu(W) clc disp('                        

任意两点间的最短路问题 Floyd-Warshall算法

这一算法与之前的Bellman-F=Ford算法一样,都可以判断负环 只需要检查dp [i] [j] 是负数的顶点i即可 1 // 求解任意两点间的最短路径问题 2 // Floyed-Warshall算法 3 // 复杂度O(N^3),N为顶点数 4 5 #include <cstdio> 6 #include <iostream> 7 8 using namespace std; 9 // 用dp的思路来求解 10 // dp[k][i][j]:从i到j,只利用前K个节点的最短

基于pgrouting的任意两点间的最短路径查询函数二

在前面的博文中写过一篇查询任意两点间最短路径的函数,当时对pgrouting不熟悉,功能很low.现在对该函数进行扩展,支持用户自己输入查询的数据库表,这一点看似简单,其实意义很大,在做室内导航的时候当用户所在的楼层变化的时候最短路径函数查询的数据表名称也会发生变化,不可能一栋大楼里的道路都是一样的吧,另外进行跨楼层的最短路径规划时,需要查询从A到楼梯口的最短路径和楼梯口到B的最短路径,这些都需要进行最短路径规划的时候能够自己选择数据表. DROP FUNCTION pgr_fromAtoB(t

基于pgrouting的任意两点间的最短路径查询函数

前面文章介绍了如何利用postgresql创建空间数据库,建立空间索引和进行路径规划.但是在真实的场景中用户进行路径规划的时候都是基于经纬度数据进行路径规划的,因为用户根本不会知道道路上节点的ID.因此文本讲述如何查询任意两点间的最短路径. 一.定义函数名及函数参数 函数名定义为: pgr_fromAtoB 参数设置分别为: 输入为数据库表名,起点和终点的经纬度坐标 输出为:路段序号,gid号,道路名,消耗及道路集合体. IN tbl varchar, --数据库表名 IN x1 double

任意两点间最短距离floyd-warshall ---- POJ 2139 Six Degrees of Cowvin Bacon

floyd-warshall算法 通过dp思想 求任意两点之间最短距离 重复利用数组实现方式dist[i][j] i - j的最短距离 for(int k = 1; k <= N; k++) for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]); 非常好实现 O(V^3) 这里贴一道刚好用到的题 http://poj.org

Openlayers3 计算地图上任意两点间的距离

主要用的接口是new ol.Sphere(6378137).haversineDistance([x1,y1],[x2,y2]): 4326坐标系中计算两点距离的方式为: var a = new ol.Sphere(6378137).haversineDistance([120.21592590991689, 30.210793016606],[120.21670777384473, 30.211168525868086]); 版权声明:本文为博主原创文章,未经博主允许不得转载.