图论模型简介一、图及其矩阵表示1、起源:哥尼斯堡七桥问题:欧拉为了解决这个问题,建立数学模型:陆地——点,桥——边,得到一个有四个“点”,七条“边”的“图”。
问题转化为能否从任一点出发一笔画出七条边再回到起点。
欧拉考察了一般一笔画的结构特点,给出了一笔画判定法则:图是连通的,且每个顶点都与偶数条边相关联(这种图称为欧拉图)。
由此可以得出结论:七桥问题无解。
2、基本概念:图(graph):由顶点和边(又称线,边的两端必须是顶点)组成的一个结构。
邻接:一条边的两个端点称是邻接的;关联:边与其两端的顶点称是关联的。
无向图(graph):边无方向的图;有向图(digraph):边有方向的图。
路(path):由相邻边组成的序列,其中中间顶点互不相同。
圈(cycle):首、尾顶点相同的路,即闭路。
连通图(connected graph):图中任意两顶点间都存在路的图。
树(tree):无圈连通图完全图(complete graph):任意两个顶点之间都有边相连的无向图,记为K n。
竞赛图(tournament):由完全图给每条边定向而得到的有向图。
二部图(bipartite graph):图的顶点分成两部分,只有不同部分顶点之间才有边相连。
图G的子图H(subgraph):H是一个图,H的顶点(边)是图G的顶点(边)。
网络(Network):边上赋了权的有向图。
3、图的矩阵表示无向图 有向图010001011001011011000100⎡⎤⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎢⎥⎣⎦ ⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎣⎡01100101000001001000001104、著名的图论问题例1 最短路问题(shortest path problem)出租车司机要从城市甲地到乙地,在纵横交错的路中如何选择一条最短的路线?例2 最小生成树问题(minimum-weight spanning tree problem)为了给小山村的居民送电,每户立了一根电杆,怎样连接可使连线最短?例3 中国邮递员问题(chinese postman problem)一名邮递员负责投递某个街区的邮件。
如何为他设计一条最短的投递路线?例4(二部图的)最优匹配问题(optimum matching)在赋权二部图中找一个权最大(最小)的匹配。
例5 旅行推销员问题(traveling salesman problem-TSP)一名推销员准备前往若干城市推销产品。
如何为他设计一条最短的旅行路线?例6 网络流问题(network flow problem)如何在一个有发点和收点的网络中确定具有最大容量的流。
二、求最短路的迪克斯特拉(Dijkstra )算法基本思想是按距0u 由近到远的顺序,依次确定0u 到G 的各顶点的最短路和距离。
为避免重复并保留每一步的计算信息,采用标号算法。
Dijkstra 算法如下:STEP1:1()0l u =,1v u ∀≠,∞=)(v l ,1{}S u =,1i =;STEP2:v S ∀∈(\S V S =),)(v l <- min {(),()()}i i l v l u w u v +, 1i i =+,计算min{()}v Sl v ∈,记达到这个最小值的一个顶点为i u ,令{}i S S u = ; STEP3:若||i V =,停止;否则,转STEP2。
例 求右图中从顶点u1到其它各点的最短路及相应的路径.求解过程列表如下:例 1 某公司在六个城市621,,,c c c 中有分公司,从i c 到j c 的直接航程票价记在下述矩阵的),(j i 位置上。
(∞表示无直接航路),请帮助该公司设计一张城市1c 到其它城市间的票价最便宜的路线图。
⎥⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎢⎣⎡∞∞∞∞∞∞055252510550102025251001020402010015252015050102540500解 第一个城市到其它城市的最短路径的Matlab 程序如下: clear; clc; M=10000;a(1,:)=[0,50,M,40,25,10];a(2,:)=[zeros(1,2),15,20,M,25];a(3,:)=[zeros(1,3),10,20,M];a(4,:)=[zeros(1,4),10,25];a(5,:)=[zeros(1,5),55];a(6,:)=zeros(1,6);a=a+a';pb(1:length(a))=0;pb(1)=1; % 永久标号点index1=1; % 标记确定为永久标记的次序index2=ones(1,length(a));%标记最短路上各点的先驱顶点d(1:length(a))=M;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]; % 记录新永久标号点index=index1(find(d(index1)==d(temp)-a(temp,index1))); % 确定前驱顶点if length(index)>=2 % 前驱顶点多于1个时取第一个index=index(1);endindex2(temp)=index; % 记录前驱顶点endd, index1, index2运行结果d = 0 35 45 35 25 10 index1 = 1 6 5 2 4 3 index2 = 1 6 5 6 1 1 动态规划方法基本方程: )}())(,(min{)(1++=k k k k k k x L x u x D x LLINGO 程序model : ! 动态规划方法;SETS : !CITIES 表示由1~9组成的集合,是一个基本集合; CITIES /1..9/: L; !属性L(i)表示城市i 到城市1的最优行驶路线的路长; ROADS(CITIES, CITIES)/ ! ROADS 表示网络中的弧,是由CITIES 派生的集合; 1,2 1,3 1,4 !并非所有城市间都有道路直接连接,故将弧具体列出; 2,5 2,6 3,5 3,6 4,5 4,6 5,7 5,8 6,7 6,87,9 8,9 /: D; !属性 D(i,j) 是城市i到j的直接距离(已知); ENDSETSDATA:D = 6 3 3 ! D赋值的顺序对应于ROADS中的弧的顺序;6 5 8 67 46 7 8 95 6;ENDDATAmin=L(1);L(9) = 0; !边界条件;@FOR( CITIES(i)| i #LT# 9: !集合循环语句, #LT#表示逻辑关系"小于";L(i) = @MIN( ROADS(i,j)|i #LT# j: D(i,j) + L(j)) ); !这就是动态规划基本方程; end(0-1)规划解法LINGO程序model: ! (0,1)--规划方法;SETS:CITIES /1..9/;ROADS(CITIES, CITIES)|&1 #LT# &2: D,x; ENDSETSDATA:D = 6 3 3 1000 1000 1000 1000 1000 1000 1000 6 5 1000 1000 10001000 8 6 1000 1000 10007 4 1000 1000 10001000 6 7 10008 9 10001000 56;ENDDATAmin=@SUM(ROADS:D*x);@SUM(CITIES(j)|j#GT#1:x(1,j))=1;@SUM(CITIES(i)|i#LT#9:x(i,9))=1;@FOR(CITIES(i)|i#GT#1 #and# i#LT#9:@SUM(CITIES(j)|j#GT#i:x(i,j))=@SUM(CITIES(j)|j#LT#i:x(j,i)));@FOR(ROADS:@BIN(x));end三、求最小生成树的prim算法设置两个集合P 和Q ,其中P 用于存放G 的最小生成树的顶点,Q 存放G 的最小生成树的边。
令P 的初值为}{1v P =(假设构造最小生成树时,从顶点1v 出发),Q 的初值为Φ=Q 。
prim 算法的思想是,从所有,(,)P V P -的边中,选取具有最小权值的边pv ,将顶点v 加入P 中,将边pv 加入Q 中,如此不断重复,直到V P =时,最小生成树构造完毕。
prim 算法如下:STEP1:}{1v P =,Φ=Q ;STEP2:while V P =~},,min(P V v P p w pv pv -∈∈=}{v P P +=,}{pv Q Q +=end例2 用prim 算法求右图的最小生成树。
解 用nr e s u l t ⨯3的第一、二、三行分别表示生成树边的起点、终点、权集合。
Matlab程序如下:clc;clear;M=1000;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;zeros(2,7)];a=a+a';a(find(a==0))=M;result=[];p=1; % 设置生成树的起始顶点tb=2:length(a); % 设置生成树以外顶点while length(result)~=length(a)-1 % 边数不足顶点数-1temp=a(p,tb);temp=temp(:); % 取出与p关联的所有边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))=[]; % 缩减生成树以外顶点endresultweight=sum(result(3,:)) % 计算最小生成树的权运行结果result = 1 2 5 4 4 72 5 4 6 7 350 40 50 30 42 45weight = 257四、求最大匹配的匈牙利算法0、从任意一个匹配M开始;1、若M饱和X的每个顶点,结束;否则,设u是X中的M非饱和顶点,置S={u},T=Φ;2、若N(S)=T, 停止;否则,设y∈N(S) \ T;3、若y是M饱和的,设yz∈M,S←S∪{z}, T←T∪{y}, 转2;否则,设P是M可扩(u,y)路, M←ME(P), 转1。