弗洛伊德算法
弗洛伊德算法(Floyd Algorithm)也叫作插点法,是解决任意两点间的最短路径的一种算法,可以处理有向图或负权边的图,同时也被用于计算有向图的传递闭包。以下是弗洛伊德算法的全部知识点:
1. 原理:动态规划思想
弗洛伊德算法采用了动态规划思想,即利用已知最短路径,逐步推导出其他节点之间的最短路径。因此,弗洛伊德算法是一个迭代算法,每一轮迭代都会增加一个节点,直到求出所有节点之间的最短路径。
2. 时间复杂度:O(n^3)
由于弗洛伊德算法需要三重循环,因此时间复杂度为O(n^3),其中n为节点数。
3. 算法步骤
(1) 初始化:将所有节点之间的距离初始化为无穷大。
(2) 对于每对相邻节点,如果它们之间有边,则将它们之间的距离设为边的权重。
(3) 对于每个节点k,判断是否可以通过节点k缩短从节点i到节点j的距离。如果可以,则更新节点i到节点j的距离。
(4) 重复执行步骤(3),直到所有节点之间的最短路径都被求出。
4. 算法优化
弗洛伊德算法可以通过一些优化来提高效率,比如:
(1) 采用邻接矩阵存储图的数据结构,以提高查找边的权重的效率。
(2) 通过剪枝优化,即当节点k不能缩短节点i到节点j的距离时,就不再继续更新节点i到节点j的距离。
(3) 采用并行计算的方法,将三重循环并行化,以提高算法的执行效率。
5. 应用场景
弗洛伊德算法适用于求解任意两点间的最短路径,尤其是当图中存在负权边时。在实际应用中,弗洛伊德算法被广泛应用于网络路由算法、城市交通规划、航空路线规划等领域。
代码实现
//创建顶点名称,获取方便后面打印路径
String[] vax={"A","B1","B2","B3","C1","C2","C3","D1","D2","E"};
//创建邻接矩阵
int[][] matrix={
{0,4,3,0,0,0,0,0,0,0},
{4,0,0,0,5,0,0,0,0,0},
{3,0,0,2,0,4,0,0,0,0},
{0,0,2,0,3,5,6,7,8,9},
{0,5,0,3,0,6,-1,-2,-3,-4},
{0,-1,-2,-3,-4,-5,-6,-7,-8,-9},
{6,-7,-8,-9,-10,-11,-12,-13,-14,-15},
{7,-8,-9,-10,-11,-12,-13,-14,-15,-16},
{8,-9,-10,-11,-12,-13,-14,-15,-16,-17},
{9,-10,-11,-12,-13,-14,-15,-16,-17}
};
//创建路径矩阵
int[][] path=new int[vax.length][vax.length];
//初始化路径矩阵
for(int i=0;i<vax.length;i++){
for(int j=0;j<vax.length;j++){
path[i][j]=j;
}
}
//弗洛伊德算法
for(int k=0;k<vax.length;k++){
for(int i=0;i<vax.length;i++){
for(int j=0;j<vax.length;j++){
if(matrix[i][k]+matrix[k][j]<matrix[i][j]){
//更新最短距离
matrix[i][j]=matrix[i][k]+matrix[k][j];
//更新路径
path[i][j]=path[i][k];
}
}
}
}
//打印最短距离和路径
for(int i=0;i<vax.length;i++){
for(int j=0;j<vax.length;j++){
System.out.print(vax[i]+"到"+vax[j]+"的最短距离为:"+matrix[i][j]+",路径为:");
int k=i;
while(k!=j){
System.out.print(vax[k]+"->");
k=path[k][j];
}
System.out.println(vax[j]);
}
}
注意
- 弗洛伊德算法的核心思想是以每个点为「中转站」,刷新所有「入度」和「出度」的距离。
- 弗洛伊德算法的时间复杂度是O(n^3),其中n是顶点的个数,所以对于大规模的图,可能会比较耗时。
- 弗洛伊德算法需要维护一个距离矩阵和一个路径矩阵,分别记录每两个顶点之间的最短距离和最短路径。
- 弗洛伊德算法可以处理有向图和无向图,也可以处理带有负权边的图,但是不能处理有负权环的图,否则会出现无穷小的情况。