[数模笔记]图论-最短路问题

最短路问题脉络

一、最短路问题概述

最短路问题即是寻找同一个网络中的两个节点之间的一条通路,使“消耗”在这条通路上的权重最小的问题,这里的权重可替换为最小距离、最短时间、最小成本等。常见的最短路问题可以体现为如下形式:“已知连接若干个城镇的铁路网络,在这个网络的两个指定城镇间,找一条最短铁路线。”

在明确最短路问题的定义之后,我们接下来需要将最短路问题通过数学形式表示出来。最短路问题发生在二维空间的一张“网络”中,故需要包含三方面信息:节点信息(存在有哪些城镇?)、边信息(连接各个城镇的铁路有哪些?)、权重信息(各个城镇之间的铁路长度是多少?)。我们使用邻接矩阵将上述三方面统一的表示在一个矩阵中:
在这里插入图片描述
显然邻接矩阵元素 w i j w_{ij} wij储存着 i i i j j j节点之间通路的信息(是否存在通路?通路的权重是多少?)。当节点间不存在通路连接时,我们使用0或无穷作为该位置的元素值,然而事实上,直接使用无穷赋值是更直接的做法。注意:在有向图问题中,邻接矩阵是一个主对角线为0的方阵,此时 w i j w_{ij} wij w j i w_{ji} wji意义不同;而在无向图问题中,邻接矩阵是一个对角阵。

二、单源最短路问题

指定一个节点作为起点(源),求其到其余各节点的最短距离,这样的问题被称为单源最短路问题。解决单源最短路的方法大体分为两种:Dijkstra算法、数学规划法。

2.1 Dijkstra算法

Dijkstra算法的思想核心是:任一节点到起点的最短路径在一定程度上是相似的,且越靠近起点的位置路径的相似程度就越高。这个思想不难理解,小明与小张住在一个小区,小明住在5号楼3单元3楼,小张住在5号楼2单元6楼,那么小明与小张从小区门口到自家楼下这段路的最短路径是完全一样的。由此我们可以推断:起点到某一节点的最短路径有很大概率是在已存在的最短路径上延伸的

2.1.1 算法流程

我们已经知道,起点到各个节点的最短路径在开始的数个节点是大概率相似的,我们称这部分相似的节点集合为 P P P集(我们也可以叫它“已经历点集”),显然 P P P集是由数个与起点直接/间接存在最短路径的优质节点组成的。我们需要做的是不断将 P ˉ \bar{P} Pˉ集(未经历点集)中的节点 x x x到起点的直接距离 l 1 l_{1} l1(原距离)与 x x x通过 P P P集作为中转到达起点的间接距离 l 2 l_{2} l2(延伸距离)进行比较,选择二者中较小者作为该节点下一次迭代的路径长度,在如此遍历一遍 P ˉ \bar{P} Pˉ集后,选择其中路径最短者纳入 P P P集组成已存在的最短路径,进行下一轮的比较,如此往复直至所有节点被纳入 P P P中。

Dijkstra算法的流程可以通过以下方式进行描述,但是稍有些晦涩:
在这里插入图片描述
此处 u 0 u_{0} u0是指起点, v v v指未经历的节点, S i S_{i} Si P P P集, S ˉ i \bar{S}_{i} Sˉi指第 i i i次迭代产生的 P ˉ \bar{P} Pˉ集, V V V集是节点集, ∣ V ∣ |V| V指节点集中节点个数, l ( x ) l(x) l(x) x x x节点到起点的距离。

2.1.2 求解某城到各个城镇距离(无向图)

例1 某公司在六个城市 c 1 , c 2 , . . . , c 6 , c_{1},c_{2},...,c_{6}, c1,c2,...,c6,中有分公司,从 c i c_{i} ci c j c_{j} cj的直接航程票价记在下述矩阵的 ( i , j ) (i, j) (i,j) 位置上( ∞ \infty 表示无直接航路)。请帮助该公司设计一张城市 c 1 c_{1} c1 到其它城市间的票价最便宜的路线图。
[ 0 50 ∞ 40 25 10 50 0 15 20 ∞ 25 ∞ 15 0 10 20 ∞ 40 20 10 0 10 25 25 ∞ 20 10 0 55 10 25 ∞ 25 55 0 ] \left[\begin{array}{cccccc}{0} & {50} & {\infty} & {40} & {25} & {10} \\ {50} & {0} & {15} & {20} & {\infty} & {25} \\ {\infty} & {15} & {0} & {10} & {20} & {\infty} \\ {40} & {20} & {10} & {0} & {10} & {25} \\ {25} & {\infty} & {20} & {10} & {0} & {55} \\ {10} & {25} & {\infty} & {25} & {55} & {0}\end{array}\right] 050402510500152025150102040201001025252010055102525550
首先规定几个变量:

变量名意义
p b ( i ) pb_{(i)} pb(i)表示 i i i顶点是否已经成为 P P P集的成员,0-1逻辑表示
i n d e x 1 ( i ) index1_{(i)} index1(i)节点纳入 P P P集的顺序。 i i i位置上存放着第 i i i个纳入 P P P集的节点序号
i n d e x 2 ( i ) index2_{(i)} index2(i)存放着路径中 i i i节点前一节点的序号信息,通过该变量可以找出路径连线
d ( i ) d_{(i)} d(i) i i i位置上存放着由起点到第 i 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;%起点的设置,需要更改!

%%%%%%Dijkstra算法部分,无需更改%%%%%%
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

2.1.3 求解某两城间最小距离

对于已知网络的邻接矩阵(有向/无向图)问题,参考司守奎建模书有以下函数可以直接给出某两城间最短距离。

function [mydistance,mypath]=mydijkstra(a,sb,db);
% 输入: a—邻接矩阵(aij)是指i到j之间的距离,可以是有向的
% sb—起点的标号, db—终点的标号
% 输出: mydistance—最短路的距离, mypath—最短路的路径
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

2.2 数学规划法

我们也可以从数学规划的角度来解决单源最短路问题,我们仍然使用邻接矩阵来表示网络的信息

W i j = {  Weight, v i v j ∈ E ∞ ,  Others \mathcal{W}_{i j}=\left\{\begin{array}{c}{\text { Weight,\qquad}v_{i} v_{j} \in E} \\ { \infty,\qquad\text { Others}}\end{array}\right. Wij={ Weight,vivjE Others
其中 E E E表示网络中通路的集合。若要求得某个网络中1节点到 n n n节点的最短路径,我们可以建立以下数学规划模型:

在这里插入图片描述
决策变量 x i j x_{ij} xij是逻辑变量,对于通路 v i v j v_{i} v_{j} vivj若它存在于1节点到 n n n节点的最短路径上 x i j x_{ij} xij值为1,反之为0。目标函数也很好理解,使路径上所有通路的权值最小即是求得最短路径。而第一个约束条件的理解稍复杂些,它限制了从起点到结束点的路径是一条不重复的、没有分叉的连线。

我们首先对约束的左侧进行分析:
∑ j = 1 v i v j ∈ E n x i j − ∑ j = 1 v j v i ∈ E n x j i \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}-\sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i} vivjEj=1nxijvjviEj=1nxji
∑ j = 1 v i v j ∈ E n x i j \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j} vivjEj=1nxij j j j进行累加,表示的是以 i i i城作为起点的通路个数之和;同理 ∑ j = 1 v j v i ∈ E n x j i \sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i} vjviEj=1nxji表示的是以 i i i城作为终点的通路个数之和。所以约束左侧的意义是: i i i节点作为起点的通路个数与以 i i i节点作为终点的通路个数之差。

根据常识我们知道,当i节点作为整个路径的始端时,只有1条通路以i城作为起点,没有通路以i城作为终点,即 ∑ j = 1 v i v j ∈ E n x i j = 1 \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}=1 vivjEj=1nxij=1 ∑ j = 1 v j v i ∈ E n x j i = 0 \sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i}=0 vjviEj=1nxji=0。故我们可以得到:
∑ j = 1 v i v j ∈ E n x i j − ∑ j = 1 v j v i ∈ E n x j i = 1 i = 1 \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}-\sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i}=1\qquad i=1 vivjEj=1nxijvjviEj=1nxji=1i=1
同理,当i节点作为整个路径的末端时,没有通路以i城作为起点,只有1条通路以i城作为终点,即 ∑ j = 1 v i v j ∈ E n x i j = 0 \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}=0 vivjEj=1nxij=0 ∑ j = 1 v j v i ∈ E n x j i = 1 \sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i}=1 vjviEj=1nxji=1,易得:
∑ j = 1 v i v j ∈ E n x i j − ∑ j = 1 v j v i ∈ E n x j i = − 1 i = n \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}-\sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i}=-1\qquad i=n vivjEj=1nxijvjviEj=1nxji=1i=n
而当i节点作为一条不分叉路径中间的一个节点时,以i城作为起点的通路数与以i城作为终点的通路数相等,即 ∑ j = 1 v i v j ∈ E n x i j = ∑ j = 1 v j v i ∈ E n x j i \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}=\sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i} vivjEj=1nxij=vjviEj=1nxji,亦即
∑ j = 1 v i v j ∈ E n x i j − ∑ j = 1 v j v i ∈ E n x j i = 0 i ≠ 1 , n \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}-\sum_{j=1 \atop v_{j} v_{i} \in E}^{n} x_{j i}=0 \qquad i\neq1,n vivjEj=1nxijvjviEj=1nxji=0i=1,n
综合上述结论,我们便得到了第一条约束:
∑ j = 1 v i v j ∈ E n x i j − ∑ j = 1 v j v i = E n x j i = { 1 , i = 1 − 1 , i = n 0 , i ≠ 1 , n \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}-\sum_{j=1 \atop v_{j} v_{i}=E}^{n} x_{j i}=\left\{\begin{array}{ll}{1,} & {i=1} \\ {-1,} & {i=n} \\ {0,} & {i \neq 1, n}\end{array}\right. vivjEj=1nxijvjvi=Ej=1nxji=1,1,0,i=1i=ni=1,n
而当我们想求解某两个节点 x 1 , x 2 ( x 1 , x 2 ∈ C ) x_{1},x_{2}(x_{1},x_{2}\in C) x1,x2(x1,x2C)之间的最短路径时,只需要相应的更改约束条件为下述形式即可:
∑ j = 1 v i v j ∈ E n x i j − ∑ j = 1 v j v i = E n x j i = { 1 , i = x 1 − 1 , i = x 2 0 , i ≠ x 1 , x 2 \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{i j}-\sum_{j=1 \atop v_{j} v_{i}=E}^{n} x_{j i}=\left\{\begin{array}{ll}{1,} & {i=x_{1}} \\ {-1,} & {i=x_{2}} \\ {0,} & {i \neq x_{1}, x_{2}}\end{array}\right. vivjEj=1nxijvjvi=Ej=1nxji=1,1,0,i=x1i=x2i=x1,x2

2.2.1数学规划法求解最短路问题

规划类问题使用 l i n g o lingo lingo求解会很方便,下面分别给出使用 l i n g o lingo lingo求解有向图和无向图最短路问题的示例。二者的思路整体一致,但在邻接矩阵和约束条件的构造上有细微的不同。

有向图最短路问题

在这里插入图片描述
例2 使用 l i n g o lingo lingo求解 A — D A—D AD的最短路问题。
直接给出 l i n g o lingo lingo求解代码。

model:
sets:
cities/A,B1,B2,C1,C2,C3,D/;
roads(cities,cities)/A B1,A B2,B1 C1,B1 C2,B1 C3,B2 C1,
B2 C2,B2 C3,C1 D,C2 D,C3 D/:w,x;!只有有通路的的需要有意义
endsets

data:
w=2 4 3 3 1 2 3 1 1 3 4;!按照序号顺序赋权值
enddata

n=@size(cities); !城市的个数;
min=@sum(roads:w*x);!目标函数

!!!!!!!!!!!约束条件部分!!!!!!!!!!!通过更改逻辑符号后的n与1的值可以自由设置起点与终点
@for(cities(i)|i #ne#1 #and# i #ne#n:@sum(roads(i,j):x(i,j))=@sum(roads(j,i):x(j,i)));
@sum(roads(i,j)|i #eq#1:x(i,j))=1;
@sum(roads(i,j)|j #eq#n:x(i,j))=1;
!可以省略一个约束条件,上一条约束已经限定了决策变量只能取0或1
end
无向图最短路问题

在这里插入图片描述
例3 使用 l i n g o lingo lingo求解 v 1 — v 11 v_{1}—v_{11} v1v11的最短路。
注意无向图的邻接矩阵是一个对角阵, l i n g o lingo lingo代码如下:

model:
sets:
cities/1..11/;
roads(cities,cities):w,x;
endsets
data:
w=0;
enddata
calc:
w(1,2)=2;w(1,3)=8;w(1,4)=1;
w(2,3)=6;w(2,5)=1;
w(3,4)=7;w(3,5)=5;w(3,6)=1;w(3,7)=2;
w(4,7)=9;
w(5,6)=3;w(5,8)=2;w(5,9)=9;
w(6,7)=4;w(6,9)=6;
w(7,9)=3;w(7,10)=1;
w(8,9)=7;w(8,11)=9;
w(9,10)=1;w(9,11)=2;w(10,11)=4;
@for(roads(i,j):w(i,j)=w(i,j)+w(j,i));
@for(roads(i,j):w(i,j)=@if(w(i,j) #eq# 0, 1000,w(i,j)));!相当于给无通路元素赋无穷大
endcalc
n=@size(cities); !城市的个数;
min=@sum(roads:w*x);
@for(cities(i)|i #ne#1 #and# i #ne#
n:@sum(cities(j):x(i,j))=@sum(cities(j):x(j,i)));
@sum(cities(j):x(1,j))=1;
@sum(cities(j):x(j,1))=0; !不能回到顶点1;
@sum(cities(j):x(j,n))=1;
@for(roads:@bin(x));
end

可以发现,在 l i n g o lingo lingo代码中,无向图问题比有向图问题增加了一个约束条件
∑ j = 1 v i v j ∈ E n x j 1 = 0 \sum_{j=1 \atop v_{i} v_{j} \in E}^{n} x_{j 1}=0 vivjEj=1nxj1=0
究其原因,是因为在使用 l i n g o lingo lingo编写代码时并没有严格按照数学模型来构造约束条件,导致在求解无向图问题时返回到原点的通路也会被纳入求解范围内,故需要加入约束条件进行限制。而有向图在构造邻接矩阵时规定了只有下三角阵有意义,故不会出现这种问题。此处不必过分深究。

三、多源最短路问题

最常见的求解多源最短路问题的方法是Floyd算法,这部分内容日后补充。
[2019.9.2 补充] 这部分很简单,就是求解图中每一对节点之间的最短路。(开学了,暂时没时间补。水一波……)

  • 11
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值