Dijkstra(迪杰斯特拉)算法——求单源最短路径
该算法又称为标号法。用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。
ps:该算法要求图中不存在负权边。
动画演示:
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到其他城市间票价最便宜的路线图。
- 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