关闭

[置顶] 最短路径算法(下)——弗洛伊德(Floyd)算法

标签: Floyd算法数据结构
2774人阅读 评论(10) 收藏 举报
分类:

概述

在这篇博客中我主要讲解最短路径算法中的Floyd算法,这是针对多源最短路径的一个经典算法。对于单源最短路径算法请详见我的另一篇博客:最短路径算法(上)——迪杰斯特拉(Dijikstra)算法

弗洛伊德(Floyd)算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。

算法思想与过程

(一)算法思想:
Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)。

从任意节点i到任意节点j的最短路径不外乎2种可能,一是直接从i到j,二是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

(二)算法过程
1)首先把初始化距离dist数组为图的邻接矩阵,路径数组path初始化为-1。其中对于邻接矩阵中的数首先初始化为正无穷,如果两个顶点存在边则初始化为权重   
2)对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是就更新它。
状态转移方程为
如果 dist[i][k]+dist[k][j] < dist[i][j]
则dist[i][j] = dist[i][k]+dist[k][j]

//Floyd算法(多源最短路径算法) 
bool Floyd(){
    for(int k = 1 ; k < this->Nv+1 ; k++){  //k代表中间顶点 
        for(int i = 1  ; i < this->Nv+1 ; i++){//i代表起始顶点 
            for(int j = 1 ; j < this->Nv+1 ; j++){//j代表终点 
                if(this->dist[i][k] + this->dist[k][j] < this->dist[i][j]){
                    this->dist[i][j] = this->dist[i][k] + this->dist[k][j];
                    if(i == j && this->dist[i][j] < 0){//发现了负值圈 
                        return false;
                    }
                    this->path[i][j] = k;
                }                   
            }
        }
    }
    return true; 
}

例子

我们用如下图结构来演示Floyd算法:
这里写图片描述
全部代码为:

#include <iostream>
#include <cstring>
#include <stack>
#include <queue>
using namespace std;

const int MAX = 65535;

class Graph{
    private:
        int** G;        //邻接矩阵
        int** dist;     //距离数组 
        int** path;     //路径数组 
        int Nv;         //顶点数
    public:
        //构造函数
        Graph(int nv, int ne){
            this->Nv = nv;
            G = new int*[nv+1];
            dist = new int*[nv+1];
            path = new int*[nv+1]; 
            for(int i = 0 ; i < nv+1 ; i++){
                G[i] = new int[nv+1];
                dist[i] = new int[nv+1];
                path[i] = new int[nv+1];
                memset(path[i],-1,sizeof(path[0][0])*(nv+1));
                for(int j = 0 ; j < nv+1 ; j++){
                    this->G[i][j] = this->dist[i][j] = MAX;
                } 
            }
            cout<<"请输入边与权重:"<<endl;
            for(int i = 0 ; i < ne ; i++){
                int v1,v2,weight;
                cin>>v1>>v2>>weight;
                this->G[v1][v2] = this->G[v2][v1] = weight;
                this->dist[v1][v2] = this->dist[v2][v1] = weight;
            }   
        }

        //Floyd算法(多源最短路径算法) 
        bool Floyd(){
            for(int k = 1 ; k < this->Nv+1 ; k++){  //k代表中间顶点 
                for(int i = 1  ; i < this->Nv+1 ; i++){//i代表起始顶点 
                    for(int j = 1 ; j < this->Nv+1 ; j++){//j代表终点 
                        if(this->dist[i][k] + this->dist[k][j] < this->dist[i][j]){
                            this->dist[i][j] = this->dist[i][k] + this->dist[k][j];
                            if(i == j && this->dist[i][j] < 0){//发现了负值圈 
                                return false;
                            }
                            this->path[i][j] = k;
                        }                   
                    }
                }
            }
            return true; 
        }

        //打印start顶点到end顶点的路径 
        void Print_Path(int start,int end){
            stack<int> stack;
            queue<int> queue;
            int k = this->path[start][end]; //start与end之间的路径必须经过的顶点 
            int tmp = k;        //临时保存k
            if(k == -1){    //如果start与end之间没有中间结点
                //打印start与end后结束函数 
                cout<<start<<"->"<<end<<endl;
                return;
            } 
            stack.push(k);      //中间顶点入栈 
            //首先找到start与k之间的路径
            //由于是从后往前找路径,故利用堆栈 
            while(this->path[start][k] != -1){
                stack.push(this->path[start][k]);
                k = this->path[start][k]; 
            }
            stack.push(start);
            //然后找到k与end之间的路径
            //由于是从前往后找路径,故用队列 
            while(this->path[tmp][end] != -1){
                queue.push(this->path[tmp][end]);
                tmp = this->path[tmp][end]; 
            }
            queue.push(end);
            //打印路径 
            cout<<stack.top();
            stack.pop();    
            while(!stack.empty()){
                cout<<"->"<<stack.top();
                stack.pop();
            }
            while(!queue.empty()){
                cout<<"->"<<queue.front();
                queue.pop();
            }
            cout<<endl;
        }

        void Print_Floyd(){
            int i,j,k;
            cout<<" length      path"<<endl; 
            for(i = 1 ; i < this->Nv+1 ; i++){
                for(j = i+1 ; j < this->Nv+1 ; j++){
                    cout<<i<<"->"<<j<<" ";
                    cout<<this->dist[i][j]<<"       ";  
                    this->Print_Path(i,j);
                }
                cout<<endl;
            }
        }
};

int main()
{
    cout<<"请输入顶点数与边长数:"<<endl;
    int nv,ne;
    cin>>nv>>ne; 
    Graph graph(nv,ne);
    if(graph.Floyd()){
        cout<<"各个顶点的最短路径为:"<<endl; 
        graph.Print_Floyd();
    }

    return 0;
 }  

截图如下:
这里写图片描述

9
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

数据结构之---C语言实现最短路径之Floyd(弗洛伊德)算法

数据结构之---C语言实现最短路径之Floyd(弗洛伊德)算法
  • u012965373
  • u012965373
  • 2015-08-21 23:06
  • 4070

最短路径之弗洛伊德算法(Floyd)

最短路径之弗洛伊德算法(Floyd)
  • u012965373
  • u012965373
  • 2015-08-21 21:58
  • 6925

最短路径问题---Floyd算法详解

前言 Genius only means hard-working all one’s life. Name:Willam Time:2017/3/81、最短路径问题介绍问题解释: 从图中的...
  • qq_35644234
  • qq_35644234
  • 2017-03-11 17:01
  • 21364

最短路径算法—Floyd(弗洛伊德)算法

转载自:http://www.wutianqi.com/?p=1903 Floyd-Warshall算法,简称Floyd算法,用于求解任意两点间的最短距离,时间复杂度为O(n^3)。 使用...
  • qq_31281327
  • qq_31281327
  • 2017-07-19 15:18
  • 186

最短路径算法(3)—Floyd(弗洛伊德)算法

转载来源:http://www.wutianqi.com/?p=1903
  • c8481892
  • c8481892
  • 2016-08-11 10:43
  • 365

弗洛伊德最短路径算法VC++演示源代码

  • 2015-02-03 08:27
  • 3.33MB
  • 下载

数据结构看书笔记(十)—— 求最短路径问题之--迪杰斯特拉(Dijkstra)算法和弗洛伊德(Floyd)算法

最短路径: 对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。 对于非网图来说,完全可以理解为所有边的权值都为1的网。 ...
  • lazyfennec
  • lazyfennec
  • 2016-11-07 19:45
  • 783

弗洛伊德最短路径算法

下面是我按照严蔚敏老师的C语言版数据结构P189编写的弗洛伊德算法,在VC++6.0下运行通过#include "stdio.h" #include "stdlib.h" #define MAX ...
  • zhangpeng12340302
  • zhangpeng12340302
  • 2011-05-23 22:49
  • 2858

最短路径--弗洛伊德(Floyd)算法

最短路径--弗洛伊德(Floyd)算法       最短路径问题。即寻找图中某两个特定结点间最短的路径长度。所谓图上的路径,即从图中一个起始结点到一个终止结点途中经过的所有结点序列,路径的长度...
  • itismelzp
  • itismelzp
  • 2015-10-29 22:09
  • 848

数据结构学习之弗洛伊德floyd算法求最短路径

#include "stdio.h" #include "stdlib.h" #define MAX 20 #define INFINITY 9999 typedef bool PathM...
  • earbao
  • earbao
  • 2012-10-26 12:45
  • 3176
    个人资料
    • 访问:137336次
    • 积分:4732
    • 等级:
    • 排名:第7081名
    • 原创:327篇
    • 转载:0篇
    • 译文:0篇
    • 评论:80条
    博客专栏
    最新评论