最短路径(Dijkstra、Floyd)

Dijkstra(迪杰斯特拉)算法——求单源最短路径

 

       该算法又称为标号法。用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

       ps:该算法要求图中不存在负权边。

 

   动画演示:

   《最短路径(Dijkstra、Floyd)》

 

Dijkstra算法的通用MATLAB程序

function [mydistance,mypath]=dijkstra(a,sb,db)

% 输入:a—邻接矩阵,a(i,j)是指i到j之间的距离,可以是有向的

% sb—起点的标号, db—终点的标号

% 输出:mydistance—最短路的距离, mypath—最短路的路径

n=size(a,1); %n取a的行数,即顶点个数

visited(1:n) = 0;visited(sb)=1;%记录顶点是否得到标号

distance(1:n) = inf; distance(sb) = 0; %起点到各顶点距离的初始化

 u=sb;  %u为最新的P标号顶点

parent(1:n) = 0; %前驱顶点的初始化

for i = 1: n-1

     id=find(visited==0); %查找未标号的顶点

     for v = id          

         if  a(u, v) + distance(u) < distance(v)

             distance(v) = distance(u) + a(u, v);  %修改标号值

             parent(v) = u;                                   

         end           

     end

     temp=distance;

     temp(visited==1)=inf;  %已标号点的距离换成无穷

     [t, u] = min(temp);  %找标号值最小的顶点

     visited(u) = 1;       %标记已经标号的顶点

 end

mypath = [];

if parent(db) ~= 0   %如果存在路!

    t = db; mypath = [db];

    while t ~= sb

        p = parent(t);

        mypath = [p mypath];

        t = p;     

    end

end

mydistance = distance(db);

 

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

    该算法又称为插点法。可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。

 

算法思想:

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

 

Floyd算法的通用MATLAB程序

function [dist,mypath]=floyd(a)

% 输入:a—邻接矩阵,元素(aij)是顶点i到j之间的直达距离,可以是有向的

% 输出:dist—最短路的距离;% mypath—最短路的路径

n=size(a,1); path=zeros(n);

for k=1:n

    for i=1:n

        for j=1:n

            if a(i,j)>a(i,k)+a(k,j)

                a(i,j)=a(i,k)+a(k,j);

                path(i,j)=k;

            end

        end

    end

end

dist=a;

for g=1:n

   for h=1:n

       gg=g;

        while path(gg,h)~=0&&path(path(gg,h),h)~=0

              path(g,h)=path(path(gg,h),h);

              gg=path(gg,h);     

       end

   end

end

for i=1:length(a)

    for j=1:length(a)

        parent=path(i,:); %从起点i到终点j的最短路上各顶点的前驱顶点

        parent(parent==0)=i; %path中的分量为0,表示该顶点的前驱是起点

        mypath{i,j}=[j]; t=j;

      while t~=i

        p=parent(t); mypath{i,j}=[p,mypath{i,j}];

        t=p;

      end

   end

end

例题

某公司在六个城市c1,c2,…,c6中有分公司,从ci到cj的直接航程票价记在下述矩阵的(i,j)位置上(∞表示无直接航路)。请帮助该公司设计一张城市c1到其他城市间票价最便宜的路线图。

《最短路径(Dijkstra、Floyd)》

 

  • Floyd算法的MATLAB程序

clc;clear;

n=6;a=zeros(n);

a(1,2)=50;a(1,4)=40;a(1,5)=25;a(1,6)=10;

a(2,3)=15;a(2,4)=20;a(2,6)=25;

a(3,4)=10;a(3,5)=20;

a(4,5)=10;a(4,6)=25;

a(5,6)=55;

a=a+a’;

a(a==0)=inf;%把所有零元素替换成无穷

a([1:n+1:n^2])=0;%对角线元素替换成0,matlab中数据是逐列存储的

[dist,mypath]=floyd(a)%调用自定义函数floyd

 

  • 运行结果

dist =

 

     0    35    45    35    25    10

    35     0    15    20    30    25

    45    15     0    10    20    35

    35    20    10     0    10    25

    25    30    20    10     0    35

    10    25    35    25    35     0

 

mypath =

 

[        1]   [1×3 double]    [1×3 double]   [1×3 double]   [1×2 double]   [1×2 double]

[1×3 double]   [         2]   [1×2 double]   [1×2 double]   [1×3 double]   [1×2 double]

[1×3 double]   [1×2 double]    [         3]   [1×2 double]   [1×2 double]   [1×3 double]

[1×3 double]  [1×2 double]     [1×2 double]   [        4]    [1×2 double]   [1×2 double]

[1×2 double]  [1×3 double]    [1×2 double]   [1×2 double]    [         5]   [1×3 double]

[1×2 double]   [1×2 double]   [1×3 double]   [1×2 double]    [1×3 double]    [        6]

 

求得c1到c2,…,c6的最便宜票价分别为35,45,35,25,10

 

ps:mypath的输出结果为元胞数组,可以在工作区点开显示具体结果(具体路径)

 

另注:用Dijkstra算法时邻接矩阵对角线为INF

           用Floyd算法时邻接矩阵对角线为0

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/qq_40581789/article/details/81160677
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞