【数学建模】图与网络—最短路径算法

最短路径算法

Dijkstra算法

代码示例一

1、矩阵a是存放各边权的邻接矩阵。

2、行向量 pb index1index2 ,d 分别用来存放 P 标号信息、标号顶点顺序、标号顶点索引、最短通路的值。

index2 (i) 存放始点到第 i 点最短通路i 顶点前一顶点的序号;

d(i) 存放由始点到第 i 点最短通路的值。

例如:求第一个城市到其它城市的最短路径的 Matlab 程序如下
clc,clear
a=zeros(6);
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(find(a==0))=inf

%初始化
pb(1:length(a))=0;pb(1)=1;index1=1;index2=ones(1,length(a));
d(1:length(a))=inf;d(1)=0;temp=1;

while sum(pb)<length(a)
 tb=find(pb==0);
 d(tb)=min(d(tb),d(temp)+a(temp,tb));
 tmpb=find(d(tb)==min(d(tb)));
 temp=tb(tmpb(1));
 pb(temp)=1;
 index1=[index1,temp];
 temp2=find(d(index1)==d(temp)-a(temp,index1));
 index2(temp)=index1(temp2(1));
end

d, index1, index2

代码示例二

 我们编写的从起点sb到终点db通用的Dijkstra标号算法程序如下:

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

2、sb—起点的标号, db—终点的标号

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

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

n=size(a,1); visited(1:n) = 0;
distance(1:n) = inf; % 保存起点到各顶点的最短距离
distance(sb) = 0; parent(1:n) = 0;

for i = 1: n-1
 temp=distance;
 id1=find(visited==1); %查找已经标号的点
 temp(id1)=inf; %已标号点的距离换成无穷
 [t, u] = min(temp); %找标号值最小的顶点
 visited(u) = 1; %标记已经标号的顶点
 id2=find(visited==0); %查找未标号的顶点
 for v = id2 
 if a(u, v) + distance(u) < distance(v)
 distance(v) = distance(u) + a(u, v); %修改标号值
 parent(v) = u; 
 end 
 end
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);
return

Floyd算法

代码示例一

1、a邻接矩阵,a(i,j)表示i到j的距离,i与j若不相邻则a(i,j)=无穷大

2、path矩阵表示v到u的最短路径所经过的中间点,初始值为j

clear;clc;
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';
M=max(max(a))*n^2; %M为充分大的正实数
a=a+((a==0)-eye(n))*M; %将除对角线外的零元素变为M
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
a, path

代码示例二:

我们编写的求起点 sb 到终点 db 通用的 Floyd 算法程序如下:

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

2、 sb—起点的标号;db—终点的标号

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

function [dist,mypath]=myfloyd(a,sb,db);
n=size(a,1); path=zeros(n);
for i=1:n
 for j=1:n
 if a(i,j)~=inf
 path(i,j)=j; %j 是 i 的后续点
 end
 end
end
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)=path(i,k);
 end
 end
 end
end
dist=a(sb,db);
mypath=sb; t=sb;

%将i到j的最短路径中所经过的点添加到mypath向量中
while t~=db
 temp=path(t,db);
 mypath=[mypath,temp];
 t=temp;
end

return
end

构造最小生成树

prim算法

核心思想:

1、集合P中存放最小生成树中的顶点,集合Q中存放最小生成树中的边。

初始化P={p}(从p出发),Q为空集。

2、从图中取出最小权值的边pv,将v存入P,pv存入Q,如此不断重复直到P=V,最小生成树构造完毕。

代码示例
clc;clear;
a=zeros(7);
a(1,2)=50; a(1,3)=60;
a(2,4)=65; a(2,5)=40;
a(3,4)=52;a(3,7)=45;
a(4,5)=50; a(4,6)=30;a(4,7)=42;
a(5,6)=70; 

a=a+a';a(find(a==0))=inf;
result=[];p=1;tb=2:length(a);
%矩阵result第一、二、三行分别表示生成树边的起点、终点、权集合

while length(result)~=length(a)-1
 temp=a(p,tb);temp=temp(:);
 d=min(temp);
 [jb,kb]=find(a(p,tb)==d);
 j=p(jb(1));k=tb(kb(1));
 result=[result,[j;k;d]];p=[p,k];tb(find(tb==k))=[];
end
result

Kruskal 算法

代码示例

我们用 index(2xn)   存放各边端点的信息,当选中某一边之后,就将此边对应的顶点序
号中较大序号 u 改记为此边的另一序号 v ,同时把后面边中所有序号为 u 的改记为 v
clc;clear;
a(1,2)=50; a(1,3)=60; a(2,4)=65; a(2,5)=40;
a(3,4)=52;a(3,7)=45; a(4,5)=50; a(4,6)=30;
a(4,7)=42; a(5,6)=70; 
[i,j,b]=find(a);
data=[i';j';b'];index=data(1:2,:);
loop=max(size(a))-1;
result=[];
while length(result)<loop
 temp=min(data(3,:));
 flag=find(data(3,:)==temp);
 flag=flag(1);
 v1=index(1,flag);v2=index(2,flag);
 if v1~=v2
 result=[result,data(:,flag)];
 end
 index(find(index==v2))=v1;
 data(:,flag)=[];
 index(:,flag)=[];
end
result

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值