floyd和它的拓展:
在计算机科学领域,Floyd通常指Floyd Warshall算法,由罗伯特·弗洛伊德(Robert W. Floyd)提出,这是一种用于在加权有向图中查找所有顶点对之间最短路径的算法。
算法原理
Floyd Warshall算法基于动态规划的思想。对于一个具有 (n) 个顶点的加权有向图 (G=(V, E)),用一个 (n n) 的邻接矩阵 (dist) 来存储图中顶点之间的距离,(dist[i][j]) 表示从顶点 (i) 到顶点 (j) 的当前最短距离。 算法通过三层循环来逐步更新这个距离矩阵。外层循环引入一个中间顶点 (k)((1<= k<= n)),对于每一对顶点 (i) 和 (j),检查是否可以通过中间顶点 (k) 使路径更短,即判断 (dist[i][k] + dist[k][j]) 是否小于 (dist[i][j]),如果是,则更新 (dist[i][j])。经过这 (n) 次的迭代后,(dist[i][j]) 就表示从顶点 (i) 到顶点 (j) 的真正最短距离。
算法特点
优点:能一次性求出图中所有顶点对之间的最短路径,实现相对简单,适用于稀疏图和稠密图,并且可以处理负权边(但不能处理包含负权回路的图)。
缺点:时间复杂度为 (O(n^3)),空间复杂度为 (O(n^2)),在顶点数量较大时,运行效率较低。
拓展运用的具体介绍:
传递闭包
定义与原理:传递闭包是指在有向图中,对于所有顶点对,如果存在从顶点(i)到顶点(j)的路径(可以经过多个中间顶点),则在传递闭包中存在一条从(i)到(j)的有向边。在FloydWarshall算法的基础上,将距离初始化改为可达性初始化,若有直接边相连则可达性为(1),否则为(0)。在算法过程中,若(dist[i][k]=1)且(dist[k][j]=1),则(dist[i][j]=1),表示从(i)到(j)可达。
****应用场景:****在知识图谱中,可通过传递闭包判断概念之间的间接关系。例如,已知"苹果"是"水果"的一种,"水果"是"食物"的一种,通过传递闭包可以得出"苹果"是"食物"的一种。在数据库的关系查询中,也能利用传递闭包快速判断数据之间的关联关系。
最小环问题
定义与原理:最小环是图中权值之和最小的环。在FloydWarshall算法更新最短路径的过程中,对于每个中间顶点(k),遍历所有顶点对((i, j)),若(ineq j)且(ineq k)且(jneq k),检查(dist[i][j]+weight(j, k)+weight(k, i))是否小于当前最小环的权值,如果是,则更新最小环的权值和相关顶点信息。这里(weight(j, k))和(weight(k, i))分别是边((j, k))和((k, i))的权值。
应用场景:
在电路设计中,可用于寻找电路中的最小反馈环,帮助优化电路结构,避免信号干扰等问题。在城市交通规划中,分析交通网络中的最小环可以发现一些容易造成拥堵的循环路径,从而针对性地进行交通疏导和道路规划。
网络优化
定义与原理:
在各种网络中,如通信网络、电力网络、物流网络等,将网络中的节点看作图的顶点,节点之间的连接看作边,边的权值可以表示距离、成本、传输时间等。通过FloydWarshall算法求出所有节点对之间的最短路径,从而确定最优的资源分配和传输路径。例如在物流网络中,将配送中心和客户点作为顶点,道路作为边,边的权值为运输成本或距离,利用Floyd算法找到任意两个点之间的最低成本路径,实现物流配送的优化。
应用场景:
在通信网络中,可用于规划数据传输路径,使数据在网络中传输的延迟最小或成本最低。在电力网络中,有助于确定电力传输的最佳路径,减少传输过程中的损耗。
社交网络分析
定义与原理:
在社交网络中,把用户看作顶点,用户之间的关系(如关注、好友等)看作边。FloydWarshall算法可以计算出任意两个用户之间的最短"关系链"长度。如果边有权值,比如可以表示关系的亲密度等,那么算法得到的就是加权的最短关系链。通过分析这些最短关系链,可以了解用户之间的紧密程度和信息传播的可能路径。
****应用场景:****社交媒体平台可以利用这一原理分析用户之间的社交距离,为用户推荐可能认识的人或相关的社交圈子。市场营销人员可以根据用户之间的关系链,制定更精准的营销方案,选择合适的意见领袖来推广产品,以达到更好的传播效果。
恰好经过k条边的最短路
Floyd算法通常用于解决多源最短路径问题,通过扩展也可以解决恰好经过(k)条边的最短路问题
基本思路
传统的Floyd算法通过动态规划的思想,利用状态转移方程(d[i][j]=min(d[i][j],d[i][k]+d[k][j]))来更新任意两点(i)和(j)之间的最短路径,其中(d[i][j])表示从(i)到(j)的最短距离。 为了求解恰好经过(k)条边的最短路,需要对算法进行扩展,引入一个三维数组(dp[i][j][k])来表示从(i)到(j)恰好经过(k)条边的最短路径长度。
实现步骤
-
初始化 对于(k = 0),当(i = j)时,(dp[i][j][0]=0);当(ineq j)时,(dp[i][j][0]=+无穷)。 对于(k = 1),如果(i)和(j)之间有直接边相连,(dp[i][j][1])为该边的权值;否则(dp[i][j][1]=+无穷)。
-
状态转移 对于(k > 1),状态转移方程为(dp[i][j][k]=min_{1<=slant l<=slant n}(dp[i][l][k 1]+dp[l][j][1])),其中(n)为图中顶点的个数。这个方程的含义是,从(i)到(j)恰好经过(k)条边的最短路径,是由从(i)到某个中间顶点(l)恰好经过(k 1)条边的最短路径,再加上从(l)到(j)的直接边(即经过(1)条边)的路径长度中的最小值
-
最终答案 经过上述计算后,(dp[i][j][k])中存储的就是从顶点(i)到顶点(j)恰好经过(k)条边的最短路径长度。如果(dp[i][j][k]=+无穷),则表示从(i)到(j)不存在恰好经过(k)条边的路径。
先看看原始的dp的思想来分析floyd

当然可以滚动数组优化第一维,这里就省略,具体原理看前面的背包问题的滚动数组。
牛的旅行(floyd的现实运用):


分析:
本题可利用Floyd算法求解牧场内各牧区之间的最短路径,进而找到连接两个牧场后新牧场的最小直径,以下是具体分析:
算法整体思路
-
数据初始化与牧场划分 - 读取每个牧区的坐标,根据输入的路径信息构建图的邻接矩阵。若两个牧区之间有直接路径相连,则邻接矩阵对应位置存储两点间的欧几里得距离(使用公式(d = sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2})计算);若没有直接相连,存储一个极大值(如(INT_MAX))。 - 利用深度优先搜索(DFS)或并查集算法,根据构建好的邻接矩阵判断牧区之间的连通性,从而将所有牧区划分到不同的牧场中。
-
利用Floyd算法计算各牧场内最短路径 - 对于每个划分好的牧场,使用Floyd算法计算牧场内任意两个牧区之间的最短路径。Floyd算法通过三层循环,不断尝试引入中间节点来更新两点之间的最短距离。设(dist[i][j])表示从牧区(i)到牧区(j)的最短距离,通过状态转移方程(dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]))(其中(k)为中间节点)进行迭代更新,最终得到任意两点间的最短距离。 - 遍历每个牧场的距离矩阵,找出该牧场内距离最远的两个牧区,即牧场的直径。
-
枚举连接点并计算新牧场直径 - 从两个不同的牧场中分别选取一个牧区进行枚举组合。对于每一对选取的牧区,假设分别来自牧场(A)和牧场(B),将它们连接起来(在距离矩阵中更新两点间的距离为它们的欧几里得距离)。 - 基于更新后的距离矩阵,再次使用Floyd算法计算新牧场内所有牧区之间的最短路径。 - 遍历新牧场的距离矩阵,找出新牧场的直径。
-
确定最小直径 - 记录所有枚举组合得到的新牧场直径,通过比较找出其中的最小值,该最小值即为连接两个牧场后新牧场的最小直径。

伪代码:

2,排序(传递闭包)

分析:
这道题可通过 Floyd 算法的思想结合不等式的传递性来求解,具体解析如下:
算法思路
- 初始化 :使用一个二维数组 inequality[n][n] 来表示变量之间的不等关系,其中 inequality[i][j] 表示变量 i 和变量 j 的关系。初始化时,将所有元素设为未知状态(比如设为 0 ,1 表示 i > j ,-1 表示 i < j )。
- 遍历不等式 :按照题目要求从前到后遍历每对不等关系。对于每对关系,如 A > B ,则将 inequality[A - 'A'][B - 'A'] 设为 1 ,inequality[B - 'A'][A - 'A'] 设为 -1 。然后利用 Floyd 算法的思想,通过传递性更新其他变量之间的关系。例如,若已知 A > B 且 B > C ,则可推出 A > C ,更新 inequality[A - 'A'][C - 'A'] 和 inequality[C - 'A'][A - 'A'] 。
- 判断结果 :
- 确定全部关系且无矛盾 :在每次更新完不等关系后,检查是否所有变量之间的关系都已确定(即 inequality[i][j] 不为 0 ,对于任意 i 和 j 且 i != j ),且不存在矛盾(如不存在 A > B 且 B > A 的情况)。若满足,则可以根据不等关系确定变量的次序并输出。
- 发生矛盾 :在更新不等关系的过程中,如果发现存在 inequality[i][j] 和 inequality[j][i] 同时为 1 或者同时为 -1 的情况,则说明存在矛盾,立即结束循环并输出 "有矛盾"。
- 无矛盾且未确定全部关系 :当遍历完所有不等式后,若既没有发现矛盾,也没有确定全部关系,则输出 "无定解"。

伪代码:

3,观光之旅(最小环):

分析:
Floyd 算法是一种用于求解图中所有顶点对之间最短路径的经典算法,也可以用来解决无向图的最小环问题,思路如下:
- 初始化
用一个二维数组 dist 来存储图中顶点之间的距离,dist[u][v] 表示顶点 u 到顶点 v 的距离。初始时,对于存在边 (u, v) 且边长为 l 的情况,dist[u][v]=dist[v][u]=l;若不存在直接边,则 dist[u][v]=dist[v][u]=正无穷;同时 dist[u][u]=0。
- 利用 Floyd 算法更新最短路径
Floyd 算法的核心是通过一个中间顶点 k 来不断尝试更新任意两个顶点 i 和 j 之间的最短路径。即对于每一对顶点 i 和 j,检查 dist[i][k]+dist[k][j] 是否小于当前的 dist[i][j],如果是,则更新 dist[i][j]。
- 寻找最小环
在 Floyd 算法的迭代过程中,当处理到中间顶点 k 时,此时 dist[i][j] 表示不经过编号大于 k 的顶点时,i 到 j 的最短路径。
对于每一个 k,枚举所有的 i 和 j(i<j 且 i!=k 且 j!=k),检查 dist[i][k]+dist[k][j]+图中边(i, j)的长度 是否能构成一个环。如果能构成环(即图中存在边 (i, j)),则计算该环的长度 len = dist[i][k]+dist[k][j]+图中边(i, j)的长度,并更新最小环的长度和对应的节点序列。
- 输出结果
遍历结束后,如果找到了符合条件的最小环,则按照顺序输出最小环上的所有节点;如果没有找到,则输出 No solution.。
通过这种方式,利用 Floyd 算法的特性,在更新最短路径的过程中去发现并记录最小环。
伪代码:

4:牛战(特殊化k的floyd):

分析:
这道题可以使用动态规划的方法来解决,以下是解题步骤:
- 初始化
设 dp[i][j] 表示从起点 S 恰好经过 i 条边到达节点 j 的最短路径长度。初始时,dp[0][S] = 0,对于其他 j,dp[0][j] = 正无穷。
- 构建图
用邻接表或邻接矩阵来存储无向图,这里假设使用邻接矩阵 graph,graph[u][v] 表示节点 u 和节点 v 之间边的长度,如果没有边相连,则设为 正无穷。
- 动态规划更新
配合快速幂算法优化时间复杂度
- 输出结果
最终,dp[N][E] 即为从起点 S 到终点 E 恰好经过 N 条边的最短路径长度。如果 dp[N][E] 仍然是 正无穷,说明不存在这样的路径,输出 -1(题目没明确说不存在路径的输出,但一般习惯如此)。

伪代码:
