5. 图论建模

数学建模

张瑞
中国科学技术大学数学科学学院

图论建模

此类模型的建模思想是:

  • 用图论语言表示模型的因素及其之间的联系;
  • 把实际问题转化为图论问题。

哥尼斯堡的七座桥 : 18世纪著名古典数学问题之一。在哥尼斯堡的一个公园里,有七座桥将普雷格尔河中两个岛及岛与河岸连接起来(如图)。问是否可能从这四块陆地中任一块出发,恰好通过每座桥一次,再回到起点?欧拉于1736年研究并解决了此问题,他把问题归结为如右图的“一笔画”问题,证明上述走法是不可能的。

mm5-7bridge

图与网络是运筹学(Operations Research)中的一个经典重要的分支,所研究的问题涉及经济管理、工业工程、交通运输、计算机科学与信息技术、通讯与网络技术等诸多领域。最短路问题、最大流问题、最小费用流问题和匹配问题等都是图与网络的基本问题。

  • 旅行商问题(TSP-traveling salesman problem) 一名推销员准备前往若干城市推销产品。如何为他(她)设计一条最短的旅行路线(从驻地出发,经过每个城市恰好一次,最后返回驻地)?这一问题的研究历史十分悠久,通常称之为旅行商问题。
  • 最短路问题(SPP-shortest path problem) 一名货柜车司机奉命在最短的时间内将一车货物从甲地运往乙地。从甲地到乙地的公路网纵横交错,因此有多种行车路线,这名司机应选择哪条线路呢?假设货柜车的运行速度是恒定的,那么这一问题相当于需要找到一条从甲地到乙地的最短路。

图的基本概念

直观地讲,对于平面上$n$个点,把其中的一些点对连接起来,不考虑点的位置与连线形态,这样形成的一个关系结构就是一个。 记成$G=(V,E)$$V$顶点集(所有点的集合),$E$边集(所有的连线构成的集合)。

若每个$e\in E$均是有序顶点对,则称为有向图;若每个$e\in E$均是无序顶点对,则称为无向图。若有的边有向,有的边无向,则称为混合图

若两个顶点有边相连,则称两个顶点相邻,两个点称为起点 / 终点端点。 仅含一个顶点的边称为自环。若存在两条边,它们有相同的顶点和序,则称图$G$重边。 即无重边,又无自环的图称为简单图

在无向图中,包含顶点$v$的边的个数,称为顶点的。 在有向图中,以$v$为起点的边的个数,称为点的出度,以$v$为终点的边的个数,称为顶点的入度

图的邻接矩阵(adjacency matrix)表示法

$G=(V,E)$的邻接矩阵$C=(c_{ij})$是如下定义

\[c_{ij}=\begin{cases} 1 , (v_i,v_j)\in E \\ 0 , (v_i,v_j)\notin E \end{cases} \]

如果两节点之间有一条弧,则邻接矩阵中对应的元素为1;否则为0。

  • $V$中元素的个数为$|V|=n$$E$中元素的个数$|E|=m$。则邻接矩阵是$n\times n$,其中只有$m$个非0元。
  • 如果图中的每条边都有一个(或多个)实数与之对应,称这样的图为赋权图。同样,对于网络中的权,也可以用这样的邻接矩阵表示。只是此时一条弧所对应的元素不再是1,而是相应的权而已。如果网络中每条弧赋有多种权,则可以用多个矩阵表示这些权。

例 1. 如下图所示的有向图的邻接矩阵

mm5-graphy1

\[\begin{pmatrix} 0 & 1 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 & 0 \\ \end{pmatrix} \]
  • 可以看到,这种表示法非常简单、直接。
  • 在邻接矩阵的所有$n^2$个元素中,只有$m$个为非零元。
  • 如果网络比较稀疏,这种表示法会浪费大量的存储空间,从而增加了在网络中查找弧的时间。
  • 无向图的邻接矩阵是一个对称阵。

关联矩阵表示法(incidence matrix)

$G=(V,E)$的关联矩阵$B=(b_{ij})$定义为:

\[b_{ij}=\begin{cases} 1 , & \exists v_k\in V, s.t. e_j=(v_i, v_k)\in E \\ -1 ,& \exists v_k\in V, s.t. e_j=(v_k, v_i)\in E \\ 0, & otherwise \\ \end{cases} \]

也就是说,节点$v_i$是边$e_j$的起点时,$b_{ij}=1$,是终点时,$b_{ij}=-1$,否则为$b_{ij}=0$

  • 关联矩阵中,每一行对应一个节点;每一列对应一条边。
  • 对于简单图,每一列只有2个非0元(一个$1$,一个$-1$)。
  • 对于赋权图,可以把关联矩阵增加一行,把每一条弧所对应的权存储在增加的行中。

例 2. 如下图所示的有向图的关联矩阵

mm5-graphy1

记弧的顺序为(1,2),(1,3),(2,4), (3,2),(4,3),(4,5),(5,3)和(5,4),

\[\begin{pmatrix} 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ -1 & 0 & 1 & -1 & 0 & 0 & 0 & 0 \\ 0 & -1 & 0 & 1 & -1 & 0 & -1 & 0 \\ 0 & 0 & -1 & 0 & 1 & 1 & 0 & -1 \\ 0 & 0 & 0 & 0 & 0 & -1 & 1 & 1 \\ \end{pmatrix} \]

假设弧(1,2),(1,3),(2,4),(3,2),(4,3),(4,5),(5,3)和(5,4)上的权分别为 8,9,6,4,0,3,6 和 7,则弧表表示如下

起点 1 1 2 3 4 4 5 5
终点 2 3 4 2 3 5 3 4
8 9 6 4 0 3 6 7

为了便于检索,一般按照起点、终点的字典序顺序存储弧表。

邻接表表示法

mm5-link-present

最短路问题

问题如下: 给出了一个连接若干个城镇的铁路网络,在这个网络的两个指定城镇间,找一条最短铁路线。

  • 以各城镇为图$G$的顶点$V$,两城镇间的直通铁路为图$G$相应两顶点间的边$E$,得图$G=(V,E)$。 对$G$的每一边 $e$ ,赋以一个实数 $w(e)$ 表示直通铁路的长度,定为 $e$ 的权,得到赋权图 $G$。 用邻接矩阵$W=(w_{ij})$表示$v_i$$v_j$之间的铁路距离;若它们之间没有铁路,则$w_{ij}=\infty$

  • 问题就是求赋权图 $G$ 中指定的两个顶点 $u_0$ , $v_0$间的具最小权的路。这条路叫做$u_0$ , $v_0$ 间的最短路,它的权叫做 $u_0$ , $v_0$ 间的距离,亦记作 $d(u_0,v_0)$

  • 求最短路已有成熟的算法: 迪克斯特拉(Dijkstra)算法

  • 若想求出所有顶点之间的最短路径,可以用Floyd算法

迪克斯特拉(Dijkstra)算法

  1. $l( u_0 ) = 0$ ,对 $v \neq u_0$,令 $l ( v ) = \infty$$S_0=\{u_\}, i=0$
  2. 对每个 $v\in \bar S_i$$\bar S_i = V \\ S_i$)。用
    \[\min\{l(v), l(v)+w(uv)\} \]
    代替 $l ( v )$,这里$w(uv)$表示顶点$u$,$v$之间边的权值。计算$\min \{ l ( v )\}$,把达到这个最小值的一个顶点记为$u_{i+1}$,令$S_{i+1}=S_i\cup\{u_{i+1}\}$
  3. $i = | V | − 1$ ,停止;若 $i < | V | − 1$ ,用 $i + 1$ 代替 $i$,转上一步。

例 3. 某公司在六个城市$c_1,c_2,\cdots,c_6$中有分公司,从 $c_i$$c_j$的直接航程票价记在下述矩阵的$(i,j)$位置上($\infty$表示无直接航路)。请帮助该公司设计一张城市 $c_1$到其它城市间的票价最便宜的路线图。

\[\begin{pmatrix} 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{pmatrix} \]

mm5-shortest-path-1

城市1到城市4之间的最短路径: 1-6-4

import networkx as nx

# create a undirected graphs.
G = nx.Graph()
G.add_node(1,name="1")
G.add_node(2)
G.add_node(3)
G.add_node(4)
G.add_node(5)
G.add_node(6)
# add edges with weight: price
G.add_edge(1, 2, price=50)
G.add_edge(1, 4, price=40)
G.add_edge(1, 5, price=25)
G.add_edge(1, 6, price=10)
G.add_edge(2, 3, price=15)
G.add_edge(2, 4, price=20)
G.add_edge(2, 6, price=25)
G.add_edge(3, 4, price=10)
G.add_edge(3, 5, price=20)
G.add_edge(4, 5, price=10)
G.add_edge(4, 6, price=25)
G.add_edge(5, 6, price=55)
#
sp= nx.dijkstra_path(G,1,4, weight='price')
print(sp)

Python

python networkx for graphy

networkx.dijkstra_path
    Uses Dijkstra’s Method to compute the shortest weighted path between two nodes in a graph

https://blog.csdn.net/tMb8Z9Vdm66wH68VX1/article/details/81463719

https://github.com/networkx/networkx/

https://networkx.github.io/documentation/latest/index.html

例 4. (渡河问题) 某人带狼、羊和蔬菜渡河。一小船除需要人划外,每次只能载一物过河。而人不在时,狼要吃羊,羊要吃菜。问此人应该如何过河?

模型: 转为图论中的最短路问题。

  1. 用四维向量来表示状态,其中第一个分量表示人,第二分量表示狼,第三分量表示羊,第四分量表示菜;当人或物在此岸时相应分量取1,在对岸时取0。
  2. 这个四维向量共有16种状态。由题意,有些状态不能取。如$(0,1,1,0)$表示人和菜在对岸,而狼和羊在此岸,这时,狼会吃羊,因此,这个状态是不可行的。通过穷举,所有的可行状态有
    \[\begin{aligned} (1,1,1,1), (1,1,1,0), (1,1,0,1), (1,0,1,1), (1,0,1,0) \\ (0,1,0,1), (0,1,0,0), (0,0,1,0), (0,0,0,1), (0,0,0,0) \end{aligned} \]
  1. 以这10个状态为节点,构造赋权图。若两个可行状态之间存在一个可行转移时,两顶点之间才有边连接,并且对应的权重为1。
  2. 问题变为图中寻找一条初始状态$(1,1,1,1)$到状态$(0,0,0,0)$的最短路径。

mm5-shortest-path-river

['1111', '0101', '1101', '0001', '1011', '0010', '1010', '0000']
import networkx as nx

# create a undirected graphs.
G = nx.Graph()
# add edges with weight: price
G.add_edge("1111","0101", weight=1)
G.add_edge("1110","0010", weight=1)
G.add_edge("1110","0100", weight=1)
G.add_edge("1101","0001", weight=1)
G.add_edge("1101","0101", weight=1)
G.add_edge("1101","0100", weight=1)
G.add_edge("1011","0001", weight=1)
G.add_edge("1011","0010", weight=1)
G.add_edge("1010","0000", weight=1)
G.add_edge("1010","0010", weight=1)

sp= nx.dijkstra_path(G,'1111','0000')

print(sp)

$W=v_0e_1v_1e_2\cdots e_kv_k$,其中$e_i\in E$$v_j\in V$,且$e_i=(v_{j-1},v_j)$,称$W$为图$G(V,E)$中的一条道路(walk),$k$为路长,$v_0$为起点,$v_k$为终点。若一条道路中的各边都不相同,称为(trail)。若道路中的顶点都不相同,称为轨道(path),可记为$P(v_0,v_k)$。起点与终点重合的轨道称为(cycle)。若图中任间两个顶点之间都存在道路,则称图为连通图

连通的无圈图称为,记为$T$;其度为1的顶点称为叶子顶点

若图$G=(V_G,V_E)$和树$T=(V_T,E_T)$满足$V_G=V_E$$E_T\subset E_G$,则称$T$$G$生成树

  • 一个连通图的生成树的个数很多
  • $G$是树当且仅当$G$中任两顶点有且仅有一条轨道

最小生成树

连通赋权图的具有最小权的生成树叫做最小生成树

例 5. 已知城市$i$与城市$j$之间铁路造价为$c_{ij}$,设计一个造价最低的铁路线路图。

问题的数学模型就是在一个连通赋权图上找权最小的生成树。

最小生成树有2种常用算法

  • prim 算法
  • Kruskal 算法
networkx.minimum_branching(G, attr='weight', default=1, preserve_attrs=False)[source]
    Returns a minimum branching from G.
    
maximum_flow(flowG, _s, _t, capacity='capacity', flow_func=None, **kwargs)[source]
    Find a maximum single-commodity flow.

最大流问题

例 6. 将城市$s$中的石油通过管道送到城市$t$,中间有4个中转站$v_1$, $v_2$, $v_3$, $v_4$。城市间管道的连接和容量如图,求从$s$$t$的最大流。

mm5-max-flow-1

(14, {'s': {1: 7, 3: 7}, 1: {2: 5, 3: 2}, 2: {'t': 5, 3: 0}, 3: {4: 9}, 4: {'t': 9, 2: 0}, 't': {}})
import networkx as nx

# create a undirected graphs.
G = nx.DiGraph()
# add edges with weight: capacity
G.add_edge('s', 1, capacity=8)
G.add_edge('s', 3, capacity=7)
G.add_edge(1, 3, capacity=5)
G.add_edge(1, 2, capacity=9)
G.add_edge(2, 3, capacity=2)
G.add_edge(3, 4, capacity=9)
G.add_edge(4, 2, capacity=6)
G.add_edge(2, 't', capacity=5)
G.add_edge(4, 't', capacity=10)
#
sp= nx.maximum_flow(G,'s','t')

print(sp)
  • 一个有向图$G=(V,E)$,在$V$中指定一点为发点$v_s$,另一个点为收点$v_t$,其余的叫中间点。对于每条弧$(v_i,v_j)\in E$,对应一个$c(v_i,c_j)\geq 0$(或简写$c_{ij}$),称为弧的容量。通常把这样的有向图叫作一个网络,记为$D=(V,E,C)$,其中$C=\{c_{ij}\}$

  • 所谓网络上的,是指定义在集合$E$上的函数$f=\{f_{ij}\}=\{f(v_i,v_j)\}$。并称$f_{ij}$为弧$(v_i,v_j)$上的流量

  • 一个网络的最大流量可以用标号法(Ford-Fulkerson)

一个应该满足:

  1. 容量限制: $0\leq f_{ij}\leq c_{ij}$
  2. 平衡条件:
    • 对中间节点,流出量=流入量,即
      \[\sum_{j:(v_i,v_j)\in E} f_{ij}-\sum_{j:(v_j, v_i)\in E} f_{ji}=0 \]
    • 对于发点$v_s$,有($v(f)$为流量,是发点的净输出量)
      \[\sum_{j:(v_s,v_j)\in E} f_{sj}-\sum_{j:(v_j, v_s)\in E} f_{js}=v(f) \]
    • 对于收点$v_t$,有
      \[\sum_{j:(v_t,v_j)\in E} f_{tj}-\sum_{j:(v_j, v_t)\in E} f_{jt}=-v(f) \]

最小费用最大流问题

对于网络$D=(V,E,C)$,每一个弧上除了给定的容量$c_{ij}$外,还有一个单位流量的费用$b_{ij}\geq0$。所谓最小费用最大流量问题就是求一个发点$v_s$到收点$v_t$的最大流,使总运输费用

\[\displaystyle\sum_{(v_i,v_j)\in E} b_{ij}f_{ij} \]

达到最小。

  • 由 Busacker 和 Gowan在 1961 年提出的迭代法解这类问题

例 7. 由于输油管道的长短不一或地质等原因,使每条管道上运输费用也不相同,因此,除考虑输油管道的最大流外,还需要考虑输油管道输送最大流的最小费用。

mm5-mincost-1

(205, {1: {2: 7, 3: 1}, 2: {3: 2, 't': 5}, 3: {4: 9}, 's': {1: 8, 3: 6}, 4: {2: 0, 't': 9}, 't': {}})
import networkx as nx

# create a undirected graphs.
G = nx.DiGraph()
# add edges with weight: capacity
G.add_node('s', demand = -14)  # 最大流出量是14
G.add_node('t', demand = 14)   # 收点流量是14
G.add_edge('s', 1, capacity=8, weight=2)
G.add_edge('s', 3, capacity=7, weight=8)
G.add_edge(1, 3, capacity=5, weight=5)
G.add_edge(1, 2, capacity=9, weight=2)
G.add_edge(2, 3, capacity=2, weight=1)
G.add_edge(3, 4, capacity=9, weight=3)
G.add_edge(4, 2, capacity=6, weight=4)
G.add_edge(2, 't', capacity=5, weight=6)
G.add_edge(4, 't', capacity=10, weight=7)

sp= nx.capacity_scaling(G)

print(sp)
capacity_scaling(G, demand='demand', capacity='capacity', weight='weight', heap=<class 'networkx.utils.heaps.BinaryHeap'>)[source]
    Find a minimum cost flow satisfying all demands in digraph G.

人员分派问题

例 8. (人员分派问题): 工作人员$X=\{x_1,x_2,\cdots,x_n\}$去做$n$件工作$Y=\{y_1,y_2,\cdots,y_n\}$,每人适合做其中一件或几件,问能否每人都有一份适合的工作?如果不能,最多几人可以有适合的工作?

模型: 以$X\cup Y$作为图的顶点集,且若$x_i$适合做工作$y_j$,则$(x_i,y_j)\in E$构成一条边来构造图$G=(X\cup Y, E)$。问题变为找$E$的一个最大子集,使得它们的顶点互不相同。

定义 1.
$M\subset E(G)$,且$\forall e_i,e_j\in M$$e_i$$e_j$无公共端点( $i\neq j$ ),则称$M$为图$G$ 中的一个对集$M$ 中的一条边的两个端点叫做在对集 $M$相配$M$ 中的端点称为被 $M$ 许配$G$ 中每个顶点皆被 $M$ 许配时, $M$ 称为完美对集$G$ 中已无使 $| M' | > | M |$的对集 $M'$ ,则 $M$ 称为最大对集

  • 人员分派问题就是求图的最大对集
  • 可以利用 1965 年埃德门兹(Edmonds)提出的匈牙利算法。

最优分派问题:在人员分派问题中,工作人员适合做的各项工作当中,效益未必一致,我们需要制定一个分派方案,使公司总效益最大。

  • 这个问题的数学模型是:在人员分派问题的模型中,图 $G$ 的每边加了权$w(x_i,y_j)\geq 0$,表示 $x_i$$y_j$ 工作的效益,求加权图 $G$ 上的权最大的完美对集。
  • 可以用库恩—曼克莱斯(Kuhn-Munkres)算法。

Python

  1. The Munkres module provides an implementation of the Munkres algorithm (also called the Hungarian algorithm or the Kuhn-Munkres algorithm), useful for solving the Assignment Problem. ( https://pypi.org/project/munkres/ )
  2. networkx.max_weight_matching
  3. scipy.optimize.linear_sum_assignment ( https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.linear_sum_assignment.html )

旅行商(TSP)问题

例 9. (Traveling Salesman Problem) 一名推销员准备前往若干城市推销产品,然后回到他的出发地。如何为他设计一条最短的旅行路线(从驻地出发,经过每个城市恰好一次,最后返回驻地)?这个问题称为旅行商问题

定义 2.
包含 $G$ 的每个顶点的轨叫做Hamilton(哈密顿)轨;闭的Hamilton轨叫做Hamilton圈H圈;含 Hamilton 圈的图叫做 Hamilton 图

  • 直观地讲,Hamilton 图就是从一顶点出发每顶点恰通过一次能回到出发点的那种图,即不重复地行遍所有的顶点再回到出发点。
  • 用图论的术语说,就是在一个赋权完全图中,找出一个有最小权的Hamilton 圈。称这种圈为最优圈。
  • 与最短路问题及连线问题相反,目前还没有求解旅行商问题的有效算法。所以希望有一个方法以获得相当好(但不一定最优)的解。
  • 对于规模比较小的问题,可以用穷举法。
  • 一个可行的办法是首先求一个 Hamilton 圈 $C$ ,然后适当修改 $C$ 以得到具有较小权的另一个 Hamilton 圈。修改的方法叫做改良圈算法
  • 用改良圈算法得到的结果几乎可以肯定不是最优的。为了得到更高的精确度,可以选择不同的初始圈,重复进行几次算法,以求得较精确的结果。

Python

openopt.TSP.solve
dwave_networkx.algorithms.tsp.traveling_salesman — D-Wave NetworkX 0.7.1 documentation
pip install dwave_networkx
  • https://github.com/MUSoC/Visualization-of-popular-algorithms-in-Python/tree/master/Travelling%20Salesman%20Problem
  • https://raw.githubusercontent.com/nelsonam/traveling_santa/master/traveling_santa.py

例 10. 从北京乘飞机到东京、纽约、墨西哥、伦敦、巴黎旅游,每个城市去一次再回北京,应如何安排路线,使旅程最短?

北京 东京 纽约 墨西哥 伦敦 巴黎
北京 56 35 21 51 60
东京 21 57 78 70
纽约 36 68 68
墨西哥 51 61
伦敦 13
巴黎

mm5-tsp-ex1

[0, 2, 1, 5, 4, 3]
has a distance of
211
distances=[]
#go through each type of cycle we can have (1-7)
for i in range(len(G)):#range(1,8): #1-8 because range is not inclusive
    for path in nx.all_simple_paths(G, source=0, target=i, cutoff=len(G)):
        if(len(path)==len(G)):
            distance=0
            for j in range(len(G)-1):
                distance=distance+G[path[j]][path[j+1]]['weight']
            distance=distance+G[0][i]['weight']
            #add these to a list
            distances.append((distance,path))

min_dist=distances[0][0];
min_path=[]

#find the min distance
for dist in distances:
    if(dist[0]<=min_dist):
        min_dist=dist[0]
        min_path=dist[1]

print(min_path)

中国邮递员问题

例 11. (Chinese Postman Problem) 一位邮递员从邮局选好邮件去投递,然后返回邮局,当然他必须经过他负责投递的每条街道至少一次,为他设计一条投递路线,使得他行程最短。

定义 3.
经过 $G$ 的每条边的迹叫做 $G$Euler 迹;闭的 Euler 迹叫做 Euler 回路E回路;含 Euler 回路的图叫做 Euler 图

  • 直观地讲,Euler 图就是从一顶点出发每边恰通过一次能回到出发点的那种图,即不重复地行遍所有的边再回到出发点。
  • 上述中国邮递员问题的数学模型是:在一个赋权连通图上求一个含所有边的回路,且使此回路的权最小。
  • 显然,若此连通赋权图是 Euler 图,则可用 Fleury 算法求 Euler 回路,此回路即为所求。
  • 对于非 Euler 图,1973 年,Edmonds 和 Johnson 给出了算法。
networkx.eulerian_circuit
    Returns an iterator over the edges of an Eulerian circuit in G.
    An Eulerian circuit is a closed walk that includes each edge of a graph exactly once.
  • https://www.datacamp.com/community/tutorials/networkx-python-graph-tutorial#solution

mm5-ccp-sleepgiant

mm5-ccp-sleepgiant-result

计划评审方法和关键路线法

计划评审方法(program evaluation and review technique, PERT)和关键路线法(critical path method, CPM)是网络分析的重要组成部分,它广泛地用于系统分析和项目管理。

计划评审与关键路线方法是在 20 世纪 50 年代提出并发展起来的,1956 年,美国杜邦公司为了协调企业不同业务部门的系统规划,提出了关键路线法。1958 年,美国海军武装部在研制“北极星”导弹计划时,由于导弹的研制系统过于庞大、复杂,为找到一种有效的管理方法,设计了计划评审方法。

由于 PERT 与 CPM 既有着相同的目标应用,又有很多相同的术语,这两种方法已合并为一种方法,在国外称为PERT/CPM,在国内称为统筹方法(scheduling method)。

例 12. 某项目工程由 11 项作业组成(分别用代号 A , B, L , J , K 表示),其计划完成时间及作业间相互关系如表所示,求完成该项目的最短时间。

作业 计划完成时间(天) 紧前作业 作业 计划完成时间(天) 紧前作业
A 5 - G 21 B, E
B 10 - H 35 B , E
C 11 - I 25 B, E
D 4 B J 15 F , G , I
E 4 A K 20 F , G
F 15 C, D

用箭线表示工作(任何消耗时间或资源的行动称为工作),用圆圈表示事件(工作的开始或结束为事件),构造计划网络图。用虚箭线表示工时为零,不消耗任何资源的虚构工作。其作用只是为了正确表示工作的前行后继关系。

mm5-plan-network-ex1

  • 也可以用圆圈表示工作,并赋权值表示工作耗时,用有向路径表示工作的前行后继关系。

mm5-cpm-ex1

$x_i$ 是事件 $i$ 的开始时间, $1$ 为最初事件, $n$ 为最终事件。希望总的工期最短,即极小化 $x_n-x_1$ 。设 $t_{ij}$ 是作业 $( i , j )$ 的计划时间,因此,对于事件 $i$ 与事件 $j$ 有不等式

\[x_j\geq x_i+t_{ij} \]

由此得到相应的数学规划问题

目标$\min(x_n-x_1)$

约束

\[\begin{cases} x_j\geq x_i+t_{ij} , (i,j)\in E, i,j\in V \\ x_i\geq 0, i\in V \end{cases} \]

其中 $V$ 是所有的事件集合, $E$ 是所有的作业集合。

计算可以得到

51
[0, 'b', 'g', 1, 'k']

其中的列表表示关键路线(Critical Path)。

mm5-plannetwork-1-cpm

参考:

  • https://www.vanforeest.com/nicky/scheduling/cpm/cpmGraph.html#cpmgraph
  • https://www.vanforeest.com/nicky/scheduling/cpm/cpmLP.html#cpmlp
  • https://github.com/chrisspen/criticalpath

关键路线可以看成是最长路,可以按照求最短路的方法(将求极小改为求极大)求出关键路线。

$x_{ij}$$0-1$ 变量,当作业 $(i, j)$ 位于关键路线上取1,否则取0。

数学规划问题写成:

目标: $\displaystyle\max \sum_{(i,j)\in E}t_{ij}x_{ij}$

约束

\[\begin{aligned} \sum_{j=1,(i,j)\in E}^n x_{ij}-\sum_{j=1,(j,i)\in E}^n x_{ji}=\begin{cases} 1, & i=1 \\ -1, & i=n \\ 0, & i\neq 1,n \end{cases} \\ x_{ij}=0\ \mbox{or}\ 1, (i,j)\in E \end{aligned} \]

例 13. 现在所列的工程要求提前完成。为提前完成工程,有些作业需要加快进度,缩短工期,而加快进度需要额外增加费用。下表列出前例中可缩短工期的所有作业和缩短一天工期额外增加的费用。现在的问题是,如何安排作业才能使额外增加的总费用最少。

作业 计划完成 最短完成 缩短 1 天增加的费用(元) 作业 计划完成 最短完成 缩短 1 天增加的费用(元)
B(1,3) 10 8 700 H(5,8)35 30 500
C(1,4) 11 8 400 I(5,7)25 22 300
E(2,5) 4 3 450J(7,8)15 12 400
G(5,6) 21 16 600 K(6,8) 20 16 500

$x_i$ 是事件 $i$ 的开始时间, $t_{ij}$ 是作业 $(i,j)$的计划时间, $m_{ij}$是完成作业$(i,j)$的最短时间,$y_{ij}$是作业$(i,j)$可能减少的时间,$c_{ij}$是作业$(i,j)$缩短一天增加的费用。有不等式

\[x_j-x_i \geq t_{ij}-y_{ij}, 0\leq y_{ij}\leq t_{ij}-m_{ij} \]

$d$ 是要求完成的天数,$1$ 为最初事件, $n$ 为最终事件,所以有 $x_n-x_1\leq d$

由此得到相应的数学规划问题

目标: 最小化额外费用 $\displaystyle\min\sum_{(i,j)\in E}c_{ij}y_{ij}$

约束

\[\begin{cases} x_j-x_i+y_{ij} \geq t_{ij} , (i,j)\in E, i,j\in V \\ x_n-x_1\leq d \\ 0\leq y_{ij}\leq t_{ij}-m_{ij}, (i,j)\in E, i,j\in V \\ \end{cases} \]

钢管订购和运输

例 14. 要铺设一条$A_1\to A_2\to\cdots\to A_{15}$的输送天然气的主管道。 经筛选后可以生产这种主管道钢管的钢厂有$S_1,\cdots,S_7$。 图中粗线表示铁路,单细线表示公路,双细线表示要铺设的管道(假设沿管道或者原来有公路,或者建有施工公路),圆圈表示火车站,每段铁路、公路和管道旁的阿拉伯数字表示里程(km)。

mm5-final-example

  • 单位钢管的铁路运价

    里程(km) ≤300 301~350 351~400 401~450 451~500
    运价(万元) 20 23 26 29 32
    里程(km) 501~600 601~700 701~800 801~900 901~1000
    运价(万元) 37 44 50 55 60

    1000km 以上每增加 1 至 100km 运价增加 5 万元。

  • 公路运输费用为 1 单位钢管每公里 0.1 万元(不足整公里部分按整公里计算)。

  • 钢管可由铁路、公路运往铺设地点(不只是运到点 $A_1$, $A_2$, $\cdots$, $A_{15}$ ,而是管道全线)。

一个钢厂如果承担制造这种钢管,至少需要生产 500 个单位。钢厂 $S_i$ 在指定期限 内能生产该钢管的最大数量为 $s_i$ 个单位,钢管出厂销价 1 单位钢管为 $p_i$ 万元;

i 1 2 3 4 5 6 7
$s_i$ 800 800 1000 2000 2000 2000 3000
$p_i$ 160 155 155 160 155 150 160
  1. 请制定一个主管道钢管的订购和运输计划,使总费用最小(给出总费用)。
  2. 请就(1)的模型分析:哪个钢厂钢管的销价的变化对购运计划和总费用影响最大,哪个钢厂钢管的产量的上限的变化对购运计划和总费用的影响最大,并给出相应的数字结果。

模型的建立与求解 记第 $i$ 个钢厂的最大供应量为 $s_i$ ,从第 $i$ 个钢厂到铺设节点 $j$ 的订购和运输费用为 $c_{ij}$ ;用 $l_j$ 表示管道第 $j$ 段需要铺设的钢管量。 $x_{ij}$ 是从钢厂 $i$ 运到节点 $j$ 的钢管量, $y_j$ 是从节点 $j$ 向左铺设的钢管量, $z_j$ 是从节点 $j$ 向右铺设的钢管量。

根据题中所给数据,我们可以先计算出从供应点 $S_i$ 到需求点 $A_j$ 的最小购运费 $c_{ij}$ (即出厂售价与运输费用之和),再根据 $c_{ij}$ 求解总费用,总费用应包括:订购费用(已包 含 在 $c_{ij}$ 中 ), 运 输 费 用 ( 由 各 厂 $S_i$ 经 铁 路 、 公 路 至 各 点 $A_j$ , $i = 1 , 2 , \cdots , 7$ ,$j = 1 , 2 , \cdots , 15$ ),铺设管道 $A_{j}A_{j+1}$ ( $j = 1 , 2 , \cdots , 14$ ) 的运费。

先算购买单位钢管及从 $S_i$ 运送到 $A_j$的最小购运费用 $c_{ij}$.

先算铁路运输费用

构造铁路距离赋权图 $G_1 = ( V , E_1 , W_1 )$ ,其中

\[V = \{ S_1,\cdots,S_7,A_1,\cdots,A_{15}, B_1,\cdots, B_{17} \} \]

$W_1=(w_{ij})$,如果$V$中的节点$i$,$j$之间有铁路连接,则取$w_{ij}$为铁路路程$d^1_{ij}$,否则,取$w_{ij}=\infty$

  • 由于铁路运费不是连续的,故不能直接用 Floyd 算法来计算最小运输费用。
  • 但可以用 Floyd 算法来计算任意两点间的最短铁路距离值,再依据题中的铁路运价表,来计算最小运输费用。
  • 最终计算出铁路任意两点间的最小运输费用 $c^1_{ij}$。其中,路径值无穷大时的费用也为无穷大。

算公路运输费用

构造公路距离赋权图 $G_2 = ( V , E_2 , W_2 )$ ,其中

\[V = \{ S_1,\cdots,S_7,A_1,\cdots,A_{15}, B_1,\cdots, B_{17} \} \]

$W_2=(w^2_{ij})$,如果$V$中的节点$i$,$j$之间有公路连接,则取$w^2_{ij}$为公路路程$d^2_{ij}$,否则,取$w^2_{ij}=\infty$

  • 用 Floyd 算法来计算任意两点间的最短公路距离值,再计算出铁路任意两点间的最小运输费用 $c^2_{ij}$
  • 路径值无穷大时的费用也为无穷大。

计算任意两点间的最小运输费用

  1. 用铁路、公路交叉运送,所以任意相邻两点间的最小运输费用为铁路、公路两者最小运输费用的最小值。 构造铁路公路的混合赋权完全图$G=(V,E,W)$,其中$W=(w_{ij})=(\min(c^1_{ij},c^2_{ij}))$
  2. 对图 $G$ 应用 Floyd 算法,就可以计算出 $S_i$$A_j$的最小运送费用 $\bar c_{ij}$
  3. 任意两点间的最小运输费用加上出厂售价,就可以计算出 $S_i$$A_j$的购买和运送最小费用$c_{ij}$

最终题目变为一个线性规划问题

目标

\[\min \sum_{i=1}^7\sum_{j=1}^{15}c_{ij}x_{ij} +\frac{0.1}2\sum_{j=1}^{15}[z_j(z_j+1)+y_j(y_j+1)] \]

约束

\[\begin{cases} \sum_{j=1}^{15}x_{ij}\in\{0\}\cup[500,s_i] , i=1,2,\cdots,7 \\ \sum_{j=1}^7x_{ij}=z_j+y_j , j=1,2,\cdots,15 \\ y_{j+1}+z_j=l_j , j=1,2,\cdots,14 \\ x_{ij}\geq 0, z_j\geq 0, y_j\geq 0, i=1,2,\cdots,7, j=1,2,\cdots, 15 \\ y_1=0, z_{15}=0 \end{cases} \]
  1. 钢厂产量约束:上限和下限(如果生产的话);
  2. 运量约束: 运输到节点$A_j$的总量( $x_{ij}$$i$ 求和)等于 $z_j$$y_j$ ;
  3. $y_{j+1}$$z_j$ 之和等于 $A_jA_{j+1}$ 段的长度 $l_j$
  4. $A_j$$A_j A_{j-1}$ 段铺设管道的运输总路程为 $1 + \cdots + y_j = y_j ( y_j + 1 ) / 2$ ;

目录

本节读完

例 15.

15.