张瑞
中国科学技术大学数学科学学院
rui@ustc.edu.cn |
此类模型的建模思想是:
哥尼斯堡的七座桥 : 18世纪著名古典数学问题之一。在哥尼斯堡的一个公园里,有七座桥将普雷格尔河中两个岛及岛与河岸连接起来(如图)。问是否可能从这四块陆地中任一块出发,恰好通过每座桥一次,再回到起点?欧拉于1736年研究并解决了此问题,他把问题归结为如右图的“一笔画”问题,证明上述走法是不可能的。
图与网络是运筹学(Operations Research)中的一个经典和重要的分支,所研究的问题涉及经济管理、工业工程、交通运输、计算机科学与信息技术、通讯与网络技术等诸多领域。最短路问题、最大流问题、最小费用流问题和匹配问题等都是图与网络的基本问题。
直观地讲,对于平面上个点,把其中的一些点对连接起来,不考虑点的位置与连线形态,这样形成的一个关系结构就是一个图。 记成,是顶点集(所有点的集合),是边集(所有的连线构成的集合)。
若每个均是有序顶点对,则称为有向图;若每个均是无序顶点对,则称为无向图。若有的边有向,有的边无向,则称为混合图。
若两个顶点有边相连,则称两个顶点相邻,两个点称为起点 / 终点 或 端点。 仅含一个顶点的边称为自环。若存在两条边,它们有相同的顶点和序,则称图有重边。 即无重边,又无自环的图称为简单图。
在无向图中,包含顶点的边的个数,称为顶点的度。 在有向图中,以为起点的边的个数,称为点的出度,以为终点的边的个数,称为顶点的入度。
图的邻接矩阵(adjacency matrix)表示法
图的邻接矩阵是如下定义
如果两节点之间有一条弧,则邻接矩阵中对应的元素为1;否则为0。
例 1. 如下图所示的有向图的邻接矩阵
|
|
关联矩阵表示法(incidence matrix)
图的关联矩阵定义为:
也就是说,节点是边的起点时,,是终点时,,否则为。
例 2. 如下图所示的有向图的关联矩阵
|
记弧的顺序为(1,2),(1,3),(2,4), (3,2),(4,3),(4,5),(5,3)和(5,4), |
假设弧(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 |
为了便于检索,一般按照起点、终点的字典序顺序存储弧表。
邻接表表示法
问题如下: 给出了一个连接若干个城镇的铁路网络,在这个网络的两个指定城镇间,找一条最短铁路线。
以各城镇为图的顶点,两城镇间的直通铁路为图相应两顶点间的边,得图。 对的每一边 ,赋以一个实数 表示直通铁路的长度,定为 的权,得到赋权图 。 用邻接矩阵表示与之间的铁路距离;若它们之间没有铁路,则。
问题就是求赋权图 中指定的两个顶点 , 间的具最小权的路。这条路叫做 , 间的最短路,它的权叫做 , 间的距离,亦记作 。
求最短路已有成熟的算法: 迪克斯特拉(Dijkstra)算法
若想求出所有顶点之间的最短路径,可以用Floyd算法
迪克斯特拉(Dijkstra)算法
例 3. 某公司在六个城市中有分公司,从 到的直接航程票价记在下述矩阵的位置上(表示无直接航路)。请帮助该公司设计一张城市 到其它城市间的票价最便宜的路线图。
城市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. (渡河问题) 某人带狼、羊和蔬菜渡河。一小船除需要人划外,每次只能载一物过河。而人不在时,狼要吃羊,羊要吃菜。问此人应该如何过河?
模型: 转为图论中的最短路问题。
['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)
设,其中,,且,称为图中的一条道路(walk),为路长,为起点,为终点。若一条道路中的各边都不相同,称为迹(trail)。若道路中的顶点都不相同,称为轨道(path),可记为。起点与终点重合的轨道称为圈(cycle)。若图中任间两个顶点之间都存在道路,则称图为连通图。
连通的无圈图称为树,记为;其度为1的顶点称为叶子顶点。
若图和树满足,,则称是的生成树。
连通赋权图的具有最小权的生成树叫做最小生成树。
例 5. 已知城市与城市之间铁路造价为,设计一个造价最低的铁路线路图。
问题的数学模型就是在一个连通赋权图上找权最小的生成树。
最小生成树有2种常用算法
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. 将城市中的石油通过管道送到城市,中间有4个中转站, , , 。城市间管道的连接和容量如图,求从到的最大流。
(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)
一个有向图,在中指定一点为发点,另一个点为收点,其余的叫中间点。对于每条弧,对应一个(或简写),称为弧的容量。通常把这样的有向图叫作一个网络,记为,其中。
所谓网络上的流,是指定义在集合上的函数。并称为弧上的流量。
一个网络的最大流量可以用标号法(Ford-Fulkerson)
一个流应该满足:
对于网络,每一个弧上除了给定的容量外,还有一个单位流量的费用。所谓最小费用最大流量问题就是求一个发点到收点的最大流,使总运输费用
达到最小。
例 7. 由于输油管道的长短不一或地质等原因,使每条管道上运输费用也不相同,因此,除考虑输油管道的最大流外,还需要考虑输油管道输送最大流的最小费用。
(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. (人员分派问题): 工作人员去做件工作,每人适合做其中一件或几件,问能否每人都有一份适合的工作?如果不能,最多几人可以有适合的工作?
模型: 以作为图的顶点集,且若适合做工作,则构成一条边来构造图。问题变为找的一个最大子集,使得它们的顶点互不相同。
定义 1.
若,且,与无公共端点( ),则称为图 中的一个对集; 中的一条边的两个端点叫做在对集 中相配; 中的端点称为被 许配; 中每个顶点皆被 许配时, 称为完美对集; 中已无使 的对集 ,则 称为最大对集。
最优分派问题:在人员分派问题中,工作人员适合做的各项工作当中,效益未必一致,我们需要制定一个分派方案,使公司总效益最大。
Python
例 9. 一名推销员准备前往若干城市推销产品,然后回到他的出发地。如何为他设计一条最短的旅行路线(从驻地出发,经过每个城市恰好一次,最后返回驻地)?这个问题称为旅行商问题。
定义 2.
包含 的每个顶点的轨叫做Hamilton(哈密顿)轨;闭的Hamilton轨叫做Hamilton圈或H圈;含 Hamilton 圈的图叫做 Hamilton 图。
Python
openopt.TSP.solve
dwave_networkx.algorithms.tsp.traveling_salesman — D-Wave NetworkX 0.7.1 documentation
pip install dwave_networkx
例 10. 从北京乘飞机到东京、纽约、墨西哥、伦敦、巴黎旅游,每个城市去一次再回北京,应如何安排路线,使旅程最短?
北京 | 东京 | 纽约 | 墨西哥 | 伦敦 | 巴黎 | |
---|---|---|---|---|---|---|
北京 | 56 | 35 | 21 | 51 | 60 | |
东京 | 21 | 57 | 78 | 70 | ||
纽约 | 36 | 68 | 68 | |||
墨西哥 | 51 | 61 | ||||
伦敦 | 13 | |||||
巴黎 | ||||||
[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. 一位邮递员从邮局选好邮件去投递,然后返回邮局,当然他必须经过他负责投递的每条街道至少一次,为他设计一条投递路线,使得他行程最短。
定义 3.
经过 的每条边的迹叫做 的 Euler 迹;闭的 Euler 迹叫做 Euler 回路或 E回路;含 Euler 回路的图叫做 Euler 图。
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.
计划评审方法(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 | ||||
用箭线表示工作(任何消耗时间或资源的行动称为工作),用圆圈表示事件(工作的开始或结束为事件),构造计划网络图。用虚箭线表示工时为零,不消耗任何资源的虚构工作。其作用只是为了正确表示工作的前行后继关系。
设 是事件 的开始时间, 为最初事件, 为最终事件。希望总的工期最短,即极小化 。设 是作业 的计划时间,因此,对于事件 与事件 有不等式
由此得到相应的数学规划问题
目标:
约束:
其中 是所有的事件集合, 是所有的作业集合。
计算可以得到
51
[0, 'b', 'g', 1, 'k']
其中的列表表示关键路线(Critical Path)。
参考:
关键路线可以看成是最长路,可以按照求最短路的方法(将求极小改为求极大)求出关键路线。
设 为 变量,当作业 位于关键路线上取1,否则取0。
数学规划问题写成:
目标:
约束:
例 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 | 450 | J(7,8) | 15 | 12 | 400 |
G(5,6) | 21 | 16 | 600 | K(6,8) | 20 | 16 | 500 |
设 是事件 的开始时间, 是作业 的计划时间, 是完成作业的最短时间,是作业可能减少的时间,是作业缩短一天增加的费用。有不等式
设 是要求完成的天数, 为最初事件, 为最终事件,所以有 。
由此得到相应的数学规划问题
目标: 最小化额外费用
约束:
例 14. 要铺设一条的输送天然气的主管道。 经筛选后可以生产这种主管道钢管的钢厂有。 图中粗线表示铁路,单细线表示公路,双细线表示要铺设的管道(假设沿管道或者原来有公路,或者建有施工公路),圆圈表示火车站,每段铁路、公路和管道旁的阿拉伯数字表示里程(km)。
单位钢管的铁路运价
里程(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 万元(不足整公里部分按整公里计算)。
钢管可由铁路、公路运往铺设地点(不只是运到点 , , , ,而是管道全线)。
一个钢厂如果承担制造这种钢管,至少需要生产 500 个单位。钢厂 在指定期限 内能生产该钢管的最大数量为 个单位,钢管出厂销价 1 单位钢管为 万元;
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
800 | 800 | 1000 | 2000 | 2000 | 2000 | 3000 | |
160 | 155 | 155 | 160 | 155 | 150 | 160 | |
模型的建立与求解 记第 个钢厂的最大供应量为 ,从第 个钢厂到铺设节点 的订购和运输费用为 ;用 表示管道第 段需要铺设的钢管量。 是从钢厂 运到节点 的钢管量, 是从节点 向左铺设的钢管量, 是从节点 向右铺设的钢管量。
根据题中所给数据,我们可以先计算出从供应点 到需求点 的最小购运费 (即出厂售价与运输费用之和),再根据 求解总费用,总费用应包括:订购费用(已包 含 在 中 ), 运 输 费 用 ( 由 各 厂 经 铁 路 、 公 路 至 各 点 , , ),铺设管道 ( ) 的运费。
先算购买单位钢管及从 运送到 的最小购运费用 .
先算铁路运输费用
构造铁路距离赋权图 ,其中
,如果中的节点,之间有铁路连接,则取为铁路路程,否则,取。
算公路运输费用
构造公路距离赋权图 ,其中
,如果中的节点,之间有公路连接,则取为公路路程,否则,取。
计算任意两点间的最小运输费用
最终题目变为一个线性规划问题
目标
约束
例 15. 谢
15.