学习知识要实时简单回顾,我把学习的图论简单梳理一下,方便入门与复习。
图论网络
图论网络简介
图论起源于 18 世纪。第一篇图论论文是瑞士数学家欧拉于 1736 年发表的“哥尼斯堡的七座桥”。1847 年,克希霍夫为了给出电网络方程而引进了“树”的概念。1857年,凯莱在计数烷 22 +nn HC 的同分异构物时,也发现了“树”。哈密尔顿于 1859 年提出“周游世界”游戏,用图论的术语,就是如何找出一个连通图中的生成圈、近几十年来,由于计算机技术和科学的飞速发展,大大地促进了图论研究和应用,图论的理论和方法已经渗透到物理、化学、通讯科学、建筑学、运筹学,生物遗传学、心理学、经济学、社会学等学科中。
图论中所谓的“图”是指某类具体事物和这些事物之间的联系。如果我们用点表示这些具体事物,用连接两点的线段(直的或曲的)表示两个事物的特定的联系,就得到了描述这个“图”的几何形象。图论为任何一个包含了一种二元关系的离散系统提供了一个数学模型,借助于图论的概念、理论和方法,可以对该模型求解。哥尼斯堡七桥问题就是一个典型的例子。在哥尼斯堡有七座桥将普莱格尔河中的两个岛及岛与河岸联结起来,问题是要从这四块陆地中的任何一块开始通过每一座桥正好一次,再回到起点。当然可以通过试验去尝试解决这个问题,但该城居民的任何尝试均未成功。欧拉为了解决这个问题,采用了建立数学模型的方法。他将每一块陆地用一个点来代替,将每一座桥用连接相应两点的一条线来代替,从而得到一个有四个“点”,七条“线”的“图”。
问题成为从任一点出发一笔画出七条线再回到起点。欧拉考察了一般一笔画的构特点,给出了一笔画的一个判定法则:这个图是连通的,且每个点都与偶数线相关联,将这个判定法则应用于七桥问题,得到了“不可能走通”的结果,不但彻底解决了这个问题,而且开创了图论研究的先河。
图与网络是运筹学(Operations Research)中的一个经典和重要的分支,所研究的问题涉及经济管理、工业工程、交通运输、计算机科学与信息技术、通讯与网络技术等诸多领域。下面将要讨论的最短路问题、最大流问题、最小费用流问题和匹配问题等都是图与网络的基本问题。
我们首先通过一些例子来了解网络优化问题。
图论问题分类
- 最短路问题(SPP-shortest path problem)
一名货柜车司机奉命在最短的时间内将一车货物从甲地运往乙地。从甲地到乙地的公路网纵横交错,因此有多种行车路线,这名司机应选择哪条线路呢?假设货柜车的运行速度是恒定的,那么这一问题相当于需要找到一条从甲地到乙地的最短路。 - 公路连接问题
某一地区有若干个主要城市,现准备修建高速公路把这些城市连接起来,使得从其中任何一个城市都可以经高速公路直接或间接到达另一个城市。假定已经知道了任意两个城市之间修建高速公路的成本,那么应如何决定在哪些城市间修建高速公路,使得总成本最小? - 指派问题(assignment problem)
一家公司经理准备安排 N 名员工去完成 N 项任务,每人一项。由于各员工的特点
不同,不同的员工去完成同一项任务时所获得的回报是不同的。如何分配工作方案可以使总回报最大? - 中国邮递员问题(CPP-chinese postman problem)
一名邮递员负责投递某个街区的邮件。如何为他(她)设计一条最短的投递路线(从邮局出发,经过投递区内每条街道至少一次,最后返回邮局)?由于这一问题是我国管梅谷教授 1960 年首先提出的,所以国际上称之为中国邮递员问题。 - 旅行商问题(TSP-traveling salesman problem)
一名推销员准备前往若干城市推销产品。如何为他(她)设计一条最短的旅行路线(从驻地出发,经过每个城市恰好一次,最后返回驻地)?这一问题的研究历史十分悠久,通常称之为旅行商问题。 - 运输问题(transportation problem)
某种原材料有 M 个产地,现在需要将原材料从产地运往 N 个使用这些原材料的工厂。假定 M 个产地的产量和 N 家工厂的需要量已知,单位产品从任一产地到任一工厂
的运费已知,那么如何安排运输方案可以使总运输成本最低?
图与网络的基本概念
无向图
有向图
完全图、二分图
子图
顶点的度
图与网络的数据结构
网络优化研究的是网络上的各种优化模型与算法。为了在计算机上实现网络优化的算法,首先我们必须有一种方法(即数据结构)在计算机上来描述图与网络。一般来说,算法的好坏与网络的具体表示方法,以及中间结果的操作方案是有关系的。这里我们介绍计算机上用来描述图与网络的 5 种常用表示方法:邻接矩阵表示法、关联矩阵表示法、弧表表示法、邻接表表示法和星形表示法。
邻接矩阵表示法
邻接矩阵表示法是将图以邻接矩阵(adjacency matrix)的形式存储在计算机中。如果两节点之间有一条弧,则邻接矩阵中对应的元素为 1;否则为 0。可以看出,这种表示法非常简单、直接。但是,在邻接矩阵的所有
n
2
n^2
n2 个元素中,只有 m个为非零元。如果网络比较稀疏,这种表示法浪费大量的存储空间,从而增加了在网络中查找弧的时间。
对于图 2 所示的有向图,可以用邻接矩阵表示为:
[
0
1
1
0
0
0
0
0
1
0
0
1
0
0
0
0
0
1
0
1
0
0
1
1
0
]
\begin{bmatrix}0&1&1&0&0\\ 0&0&0&1&0\\ 0&1&0&0&0\\ 0&0&1&0&1\\ 0&0&1&1&0\end{bmatrix}
0000010100100110100100010
关联矩阵表示法
在关联矩阵中,每行对应于图的一个节点,每列对应于图的一条弧。如果一个节点是一条弧的起点,则关联矩阵中对应的元素为 1;如果一个节点是一条弧的终点,则关联矩阵中对应的元素为 1− ;如果一个节点与一条弧不关联,则关联矩阵中对应的元素为 0。对于简单图,关联矩阵每列只含有两个非零元(一个 +1 ,一个 -1)。可以看出,这种表示法也非常简单、直接。但是,在关联矩阵的所有 nm 个元素中,只有 2m 个为非零元。如果网络比较稀疏,这种表示法也会浪费大量的存储空间。但由于关联矩阵有许多特别重要的理论性质,因此它在网络优化中是非常重要的概念.
对于上述 所示的图,如果关联矩阵中每列对应弧的顺序为(1,2),(1,3),(2,4),(3,2),(4,3),(4,5),(5,3)和(5,4),则关联矩阵表示为
[
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
0
−
1
0
0
0
0
0
0
−
1
1
1
]
\begin{bmatrix}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&0&-1\\ 0&0&0&0&0&0&-1&1&1\end{bmatrix}
1−1000010−1000010−1000−1100000−110000011000−101−1000−101−11
同样,对于网络中的权,也可以通过对关联矩阵的扩展来表示。例如,如果网络中每条弧有一个权,我们可以把关联矩阵增加一行,把每一条弧所对应的权存储在增加的行中。如果网络中每条弧赋有多个权,我们可以把关联矩阵增加相应的行数,把每一条弧所对应的权存储在增加的行中。
钢管订购和运输实战
要铺设一条
A
1
→
A
2
→
⋯
→
A
15
A_1\to A_2\to\cdots\to A_{15}
A1→A2→⋯→A15的输送天然气的主管道, 如图 所示。经筛选后可以生产这种主管道钢管的钢厂有
S
1
,
S
2
,
⋯
S
7
S_1,S_2,\cdots S_7
S1,S2,⋯S7。图中粗线表示铁路,单细线表示公路,双细线表示要铺设的管道(假设沿管道或者原来有公路,或者建有施工公路),圆圈表示火车站,每段铁路、公路和管道旁的阿拉伯数字表示里程(单位 km)。
为方便计,1km 主管道钢管称为 1 单位钢管。一个钢厂如果承担制造这种钢管,至少需要生产 500 个单位。钢厂 Si 在指定期限内能生产该钢管的最大数量为 is 个单位,钢管出厂销价 1 单位钢管为pi 万元,见表 ;1 单位钢管的铁路运价见表。
1000km 以上每增加 1 至 100km 运价增加 5 万元。公路运输费用为 1 单位钢管每公里 0.1 万元(不足整公里部分按整公里计算)。钢管可由铁路、公路运往铺设地点(不只是运到点
A
1
,
A
2
,
⋯
,
A
15
A_1,A_2,\cdots,A_{15}
A1,A2,⋯,A15,而是管道全线)。
(1)请制定一个主管道钢管的订购和运输计划,使总费用最小(给出总费用)。
(2)请就(1)的模型分析:哪个钢厂钢管的销价的变化对购运计划和总费用影响最大,哪个钢厂钢管的产量的上限的变化对购运计划和总费用的影响最大,并给出相应的数字结果。
(3)如果要铺设的管道不是一条线,而是一个树形图,铁路、公路和管道构成网络,请就这种更一般的情形给出一种解决办法,并对图 15 按(1)的要求给出模型和结果。
model:
sets:
!nodes 表示节点集合;
nodes /S1,S2,S3,S4,S5,S6,S7,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,
B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17/;
!c1(i,j)表示节点 i 到 j 铁路运输的最小运价(万元),c2(i,j)表示节点 i 到 j 公路运输的费
用邻接矩阵,c(i,j)表示节点 i 到 j 的最小运价,path 标志最短路径上走过的顶点;
link(nodes, nodes): w, c1,c2,c,path1,path;
supply/S1..S7/:S,P,f;
need/A1..A15/:b,y,z; !y 表示每一点往左铺的量,z 表示往右铺的量;
linkf(supply, need):cf,X;
endsets
data:
S=800 800 1000 2000 2000 2000 3000;
P=160 155 155 160 155 150 160;
b=104,301,750,606,194,205,201,680,480,300,220,210,420,500,0;
path1=0; path=0; w=0; c2=0;
! 以下是格式化输出计算的中间结果和最终结果;
@text(MiddleCost.txt)=@writefor(supply(i): @writefor(need(j): @format(cf(i,j),' 6.1f' )),
@newline(1));
@text(Train_path.txt)=@writefor(nodes(i):@writefor(nodes(j):@format(path1(i,j),'5.0f')),
@newline(1));
@text(Final_path.txt)=@writefor(nodes(i):@writefor(nodes(j):@format(path(i,j),'5.0f')),
@newline(1));
@text(FinalResult.txt)=@writefor(supply(i):@writefor(need(j):@format(x(i,j),'5.0f')),
@newline(1) );
@text(FinalResult.txt)=@write(@newline(1));
@text(FinalResult.txt)=@writefor(need:@format(y,'5.0f') );
@text(FinalResult.txt)=@write(@newline(2));
@text(FinalResult.txt)=@writefor(need:@format(z,'5.0f') );
enddata
calc:
!输入铁路距离邻接矩阵的上三角元素;
w(1,29)=20;w(1,30)=202;w(2,30)=1200;w(3,31)=690;w(4,34)=690;w(5,33)=462;
w(6,38)=70;w(7,39)=30;w(23,25)=450;w(24,25)=80;w(25,27)=1150;w(26,28)=306;
w(27,30)=1100;w(28,29)=195;w(30,31)=720;w(31,32)=520;w(32,34)=170;w(33,34)=88;
w(34,36)=160;w(35,36)=70;w(36,37)=320;w(37,38)=160;w(38,39)=290;
@for(link(i,j): w(i,j) = w(i, j)+w(j,i) ); !输入铁路距离邻接矩阵的下三角元素;
@for(link(i,j)|i#ne#j: w(i,j)=@if(w(i,j) #eq# 0, 20000,w(i,j))); ! 无铁路连接,元素为充分
大的数;
!以下就是最短路计算公式(Floyd-Warshall 算法);
@for(nodes(k):@for(nodes(i):@for(nodes(j):tm=@smin(w(i,j),w(i,k)+w(k,j));
path1(i,j)=@if(w(i,j)#gt# tm,k,path1(i,j));w(i,j)=tm)));
!以下就是按最短路 w 查找相应运费 C1 的计算公式;
@for(link|w#eq#0: C1=0);
@for(link|w#gt#0 #and# w#le#300: C1=20);
@for(link|w#gt#300 #and# w#le#350: C1=23);
@for(link|w#gt#350 #and# w#le#400: C1=26);
@for(link|w#gt#400 #and# w#le#450: C1=29);
@for(link|w#gt#450 #and# w#le#500: C1=32);
@for(link|w#gt#500 #and# w#le#600: C1=37);
@for(link|w#gt#600 #and# w#le#700: C1=44);
@for(link|w#gt#700 #and# w#le#800: C1=50);
@for(link|w#gt#800 #and# w#le#900: C1=55);
@for(link|w#gt#900 #and# w#le#1000: C1=60);
@for(link|w#gt#1000: C1= 60+5*@floor(w/100-10)+@if(@mod(w,100)#eq#0,0,5) );
!输入公路距离邻接矩阵的上三角元素;
c2(1,14)=31;c2(6,21)=110;c2(7,22)=20;c2(8,9)=104;c2(9,10)=301;c2(9,23)=3;
c2(10,11)=750;c2(10,24)=2;c2(11,12)=606;c2(11,27)=600;c2(12,13)=194;c2(12,26)=10;
c2(13,14)=205;c2(13,28)=5;c2(14,15)=201;c2(14,29)=10;c2(15,16)=680;c2(15,30)=12;
c2(16,17)=480;c2(16,31)=42;c2(17,18)=300;c2(17,32)=70;c2(18,19)=220;c2(18,33)=10;
c2(19,20)=210;c2(19,35)=10;c2(20,21)=420;c2(20,37)=62;c2(21,22)=500;c2(21,38)=30;
c2(22,39)=20;
@for(link(i,j): c2(i,j) = c2(i,j)+c2(j,i)); !输入公路距离邻接矩阵的下三角元素;
@for(link(i,j):c2(i,j)=0.1*c2(i,j)); ! 距离转化成费用;
@for(link(i,j)|i#ne#j: c2(i,j) =@if(c2(i,j)#eq#0,10000,c2(i,j) )); !无公路连接,元素为充分大的数;
@for(link: C= @if(C1#le#C2,C1,C2)); ! C1 和 C2 矩阵对应元素取最小;
@for(nodes(k):@for(nodes(i):@for(nodes(j):tm=@smin(C(i,j),C(i,k)+C(k,j));
path(i,j)=@if(C(i,j)#gt# tm,k,path(i,j));C(i,j)=tm)));
@for(link(i,j)|i #le# 7 #and# j#ge#8 #and# j#le# 22:cf(i,j-7)=c(i,j)); !提取下面二次规划模
型需要的 7×15 矩阵;
endcalc
[obj]min=@sum(linkf(i,j):(cf(i,j)+p(i))*x(i,j))+0.05*@sum(need(j):y(j)^2+y(j)+z(j)^2+z(j));
! 约束;
@for(supply(i):[con1]@sum(need(j):x(i,j))<= S(i)*f(i));
@for(supply(i):[con2]@sum(need(j):x(i,j)) >= 500*f(i));
@for(need(j):[con3] @sum(supply(i):x(i,j))=y(j)+z(j));
@for(need(j)|j#NE#15:[con4] z(j)+y(j+1)=b(j));
y(1)=0; z(15)=0;
@for(supply: @bin(f));
@for(need: @gin(y));
end
model:
sets:
! nodes 表示节点集合;
nodes
/S1,S2,S3,S4,S5,S6,S7,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A
17,A18,A19,A20,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12/;
!c1(i,j)表示节点 i 到 j 铁路运输的最小单位运价(万元),c2(i,j)表示节点 i 到 j 公路运输
的邻接权重矩阵,c(i,j)表示节点 i 到 j 的最小单位运价,path 标志最短路径上走过的顶
点;
link(nodes, nodes): w, c1,c2,c,path1,path;
supply/S1..S7/:s,p,f;
need/A1..A21/:b,y,z;!y 表示每一点往节点编号小的方向铺设量,z 表示往节点编号大的
方向铺设量;
linkf(supply, need):cf,x;
special/1..3/:sx; ! 铺设节点 9,11,17 往最大编号节点方向的铺设量;
endsets
data:
s=800 800 1000 2000 2000 2000 3000;
p=160 155 155 160 155 150 160;
b=104,301,750,606,194,205,201,680,480,300,220,210,420,500,42,10,130,190,260,100,0;
path1=0; path=0; w=0; c2=0;
! 以下是格式化输出计算的中间结果和最终结果;
@text(MiddleCost.txt)=@writefor(supply(i): @writefor(need(j): @format(cf(i,j),' 6.1f' )),
@newline(1));
@text(Train_path.txt)=@writefor(nodes(i):@writefor(nodes(j):@format(path1(i,j),'5.0f')),
@newline(1));
@text(Final_path.txt)=@writefor(nodes(i):@writefor(nodes(j):@format(path(i,j),'5.0f')),
@newline(1));
@text(FinalResult.txt)=@writefor(supply(i):@writefor(need(j):@format(x(i,j),'5.0f')),
@newline(1) );
@text(FinalResult.txt)=@write(@newline(1));
@text(FinalResult.txt)=@writefor(need:@format(y,'5.0f'));
@text(FinalResult.txt)=@write(@newline(2));
@text(FinalResult.txt)=@writefor(need:@format(z,'5.0f'));
enddata
calc:
!输入铁路距离邻接矩阵的上三角元素;
w(28,30)=450;w(29,30)=80;w(30,32)=1150;w(31,33)=306;w(33,34)=195;w(1,34)=20;
w(1,35)=202;w(32,35)=1100;w(2,35)=1200;w(23,35)=720;w(3,23)=690;w(23,36)=520;
w(36,37)=170;w(4,37)=690;w(5,24)=462;w(24,37)=88;w(25,37)=160;w(25,26)=70;
w(25,27)=320;w(27,38)=160;w(6,38)=70;w(38,39)=290;w(7,39)=30;
@for(link(i,j): w(i,j) = w(i, j)+w(j,i) );!输入铁路距离邻接矩阵的下三角元素;
@for(link(i,j)|i#ne#j: w(i,j)=@if(w(i,j) #eq# 0, 20000,w(i,j))); ! 无铁路连接,元素为充分
大的数;
!以下就是最短路计算公式(Floyd-Warshall 算法);
@for(nodes(k):@for(nodes(i):@for(nodes(j):tm=@smin(w(i,j),w(i,k)+w(k,j));
path1(i,j)=@if(w(i,j)#gt# tm,k,path1(i,j));w(i,j)=tm)));
!以下就是按最短路 w 查找相应运费 C1 的计算公式;
@for(link|w#eq#0: C1=0);
@for(link|w#gt#0 #and# w#le#300: C1=20);
@for(link|w#gt#300 #and# w#le#350: C1=23);
@for(link|w#gt#350 #and# w#le#400: C1=26);
@for(link|w#gt#400 #and# w#le#450: C1=29);
@for(link|w#gt#450 #and# w#le#500: C1=32);
@for(link|w#gt#500 #and# w#le#600: C1=37);
@for(link|w#gt#600 #and# w#le#700: C1=44);
@for(link|w#gt#700 #and# w#le#800: C1=50);
@for(link|w#gt#800 #and# w#le#900: C1=55);
@for(link|w#gt#900 #and# w#le#1000: C1=60);
@for(link|w#gt#1000: C1= 60+5*@floor(w/100-10)+@if(@mod(w,100)#eq#0,0,5) );
!输入公路距离邻接矩阵的上三角元素;
c2(8,9)=104;c2(9,10)=301;c2(10,11)=750;c2(11,12)=606;c2(12,13)=194;c2(13,14)=205;
c2(14,15)=201;c2(15,16)=680;c2(16,17)=480;c2(16,23)=42;c2(17,18)=300;c2(18,19)=220;
c2(18,24)=10;c2(19,20)=210;c2(20,21)=420;c2(21,22)=500;c2(24,25)=130;c2(24,26)=190;
c2(26,27)=260;c2(6,27)=100;c2(9,28)=3;c2(10,29)=2;c2(11,32)=600;c2(12,31)=10;
c2(13,33)=5;c2(14,34)=10;c2(1,14)=31;c2(15,35)=12;c2(17,36)=70;c2(19,26)=10;
c2(20,27)=62;c2(6,21)=110;c2(21,38)=30;c2(22,39)=20;c2(7,22)=20;
@for(link(i,j): c2(i,j) = c2(i,j)+c2(j,i)); !输入公路距离邻接矩阵的下三角元素;
@for(link(i,j):c2(i,j)=0.1*c2(i,j)); ! 距离转化成费用;
@for(link(i,j)|i#ne#j: c2(i,j) =@if(c2(i,j)#eq#0,10000,c2(i,j) )); ! 距离转化成费用;
@for(link: C= @if(C1#le#C2,C1,C2)); !邻接矩阵的对角线元素变为 0;
@for(nodes(k):@for(nodes(i):@for(nodes(j):tm=@smin(C(i,j),C(i,k)+C(k,j));
path(i,j)=@if(C(i,j)#gt# tm,k,path(i,j));C(i,j)=tm)));
@for(link(i,j)|i #le# 7 #and# j#ge#8 #and# j#le# 27:cf(i,j-7)=c(i,j)); !提取下面二次规划模
型需要的 7×21 矩阵;
@for(supply(i):cf(i,21)=c(i,6));
endcalc
[obj]min=@sum(linkf(i,j):(cf(i,j)+p(i))*x(i,j))+0.05*@sum(need(j):y(j)^2+y(j)+z(j)^2+z(j))+
0.05*@sum(special:sx^2+sx);
! 约束;
@for(supply(i):[con1]@sum(need(j):x(i,j))<= s(i)*f(i));
@for(supply(i):[con2]@sum(need(j):x(i,j)) >= 500*f(i));
@for(need(j)|j#ne#9 #and# j#ne#11 #and# j#ne#17:[con3] @sum(supply(i):x(i,j))=y(j)+z(j));
y(9)+z(9)+sx(1)=@sum(supply(i):x(i,9)); y(11)+z(11)+sx(2)=@sum(supply(i):x(i,11));
y(17)+z(17)+sx(3)=@sum(supply(i):x(i,17));
@for(need(j)|j #le# 14:(z(j)+y(j+1))=b(j));
@for(need(j)|j#ge#19 #and# j#le#20:z(j)+y(j+1)=b(j));
sx(1)+y(16)=42; sx(2)+y(17)=10; sx(3)+y(19)=190; z(17)+y(18)=130;
y(1)+z(15)+z(16)+z(18)+z(21)=0;
@for(supply: @bin(f)); @for(need: @gin(y));
end
编写不易,求个点赞!!!!!!!
“你是谁?”
“一个看帖子的人。”
“看帖子不点赞啊?”
“你点赞吗?”
“当然点了。”
“我也会点。”
“谁会把经验写在帖子里。”
“写在帖子里的那能叫经验贴?”
“上流!”
cheer!!!