图与网络

1. 图与网络的基本概念与数据结构

  • 一个图是由一些点以及这些点之间得连线所组成的
  • 两点间不带箭头的连线为,带箭头的连线为
  • 若边e = (u,v),则称e连接u与v;点u,v称为e的顶点
  • 如果两条边有一个公共顶点,则称这两条边是邻接的;两个顶点重合为一点的边称为

1.1 无向图

如果一个图是由点以及边所构成的,则称为无向图,记为G = (V,E),一个图称为有限图,如果它的顶点集和边集都有限。图G 的顶点数用符号V 表示,边数用 |E| 表示。

1.2 有向图

如果一个图是由点以及弧所构成的,则称为有向图,记为D = (V,A)

1.3 完全图,二分图

  • G = (V,E)是一个简单图,当满足
    |E|=\frac{|V|(|V|-1)}{2}
    每一对不同的顶点都有一条边相连的简单图称为完全图(complete graph)。
  • G = (V,E)是一个图,若存在V的一个分划(V_1,V_2),是G的每条边有一个顶点在V_1中,另一个在V_2中,则称G为二分图。

1.4 子图

1.5 顶点的度

顶点的度是指图中与顶点V相关联的边的数目

1.6 图与网络的数据结构

1.6.1 邻接矩阵表示法

定义:就是0-1矩阵,如果元素cij为“1”表示弧从第i个到第j个点,为“0”的话表示没有。如果是无向图则必定cij=cji。


1.6.2 稀疏矩阵表示法

当矩阵中0的个数比较少时,可以通过仅仅储存非0元素的坐标以及值来表示一个矩阵
像这样:

(3,1) 35
(4,1) 21
(5,1) 51
(3,2) 21
(6,5) 13

构造系数矩阵的两种方法
  1. S=sparse(X)—将矩阵X转化为稀疏矩阵的形式,即矩阵X中任何零元素去除,非零元素及其下标(索引)组成矩阵S。 如果X本身是稀疏的,sparse(X)返回S
 a=[1,0,2;0,0,1;0,0,6];
  >> a
 3
 a =
 
       1     0     2
       0     0     1
       0     0     6
 
>> b=sparse(a)
 
 b =
 
    (1,1)        1
    (1,3)        2
    (2,3)        1
    (3,3)        6
  1. S = sparse(i,j,s,m,n,nzmax)——由i,j,s三个向量创建一个m*n的稀疏矩阵(上面的B矩阵形式),并且最多含有nzmax个元素。
    例如:B=sparse([1,2,3],[1,2,3],[0,1,2],4,4,4)
    B =
    (2,2) 1

    (3,3) 2
    其中i=[1,2,3],稀疏矩阵的行位置;j=[1,2,3],稀疏矩阵的列位置;s=[0,1,2],稀疏矩阵元素值。 其位置为一一对应。
    m=4(>=max(i)),n=4(>=max(j)) (注:m和n的值可以在满足条件的范围内任意选取),用于限定稀疏的大小。
    nzmax=4(>=max(i or j)),稀疏矩阵最多可以有nzmax个元素。

2. 最短路问题

从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径。

2.1 两个指定顶点之间的最短路径

解决问题的方法:

  1. 迪杰斯特拉算法(Dijkstra算法)-----经典

  2. 弗洛伊德算法(Floyd算法)-----用三层循环
    通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入矩阵,
    矩阵S中的元素 map[i][j] 表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。
    假设图G中顶点个数为N,则需要对矩阵D和矩阵P进行N次更新。
    初始时,矩阵D中顶点 map[i][j] 的距离为顶点i到顶点j的权值;
    如果i和j不相邻,则 map[i][j]=∞。 接下来开始,对矩阵D进行N次更新。
    第1次更新时,如果”a[i][j]的距离” > “a[i][k]+a[k][j]”
    a[i][0]+a[0][j]表示”i与j之间经过第1个顶点的距离”,则更新a[i][j]为”a[i][0]+a[0][j]”。 同理,第k次更新时,如果”a[i][j]的距离” > “a[i][k-1]+a[k-1][j]”,则更新a[i][j]为”a[i][k-1]+a[k-1][j]”。更新N次之后,操作完成!

可以通过调用matlab图论工具箱中的graphshortestpath函数直接进行计算

3. 最小生成树问题

一般可以使用matlab图论工具箱中的graphminspantree()函数来求得最小生成树。
【例】



clc
clear
%将数据写成三元组的形式
x = [2,3,3,4,4,4,5,5,5,5,6,6,6,6,6];
y = [1,1,2,1,2,3,1,2,3,4,1,2,3,4,5];
w = [56,35,21,21,57,36,51,78,68,51,60,70,68,61,13];
a = sparse(x,y,w,6,6);%转为稀疏矩阵
ug = tril(a+a');%转化为下三角行列式
view(biograph(ug,[],'ShowArrows','off','ShowWeight','on'));

[st,pred]=graphminspantree(ug)%生成最小生成树
nodestr = ['L','M','N','Pe','T'];
h=view(biograph(st,nodestr,'ShowArrows','off','ShowWeights','on'));

Edges=getedgesbynodeid(h);%提取无向图h的边集
set(Edges,'LineColor',[0 0 0]);%设置颜色属性
set(Edges,'LineWidth',1.5)%设置边值属性
>>
st =

   (3,1)       35
   (4,1)       21
   (5,1)       51
   (3,2)       21
   (6,5)       13


pred =

     0     3     1     1     1     5

其中st是一个代表生成树的稀疏矩阵,pred是包含最小生成的祖先节点的向量
该图的网络如下:



该图的最小生成树如下:


4. 网络最大流问题

假设现在有一个地下水管道网络,有m根管道,n个管道交叉点,现在自来水厂位于其中一个点,向网络中输水,邻居在另外一个点接水,已知由于管道修建的年代不同,有的管道能承受的水流量较大,有的较小,现在求在自来水厂输入的水不限的情况下,邻居能接到的水的最大值?
为解决该问题,可以将输水网络抽象成一个联通的有向图,每根管道是一条边,交叉点为一个结点,从u流向v的管道能承受的最大流量称为容量,设为cap[u][v],而该管道实际流过的流量设为flow[u][v],自来水厂称为源点s,隔壁老王家称为汇点t,则该问题求的是最终流入汇点的总流量flow的最大值。

4.1 思路分析

关于最大流问题的解法大致分为两类:增广路算法和预流推进算法增广路算法的特点是代码量小,适用范围广,因此广受欢迎;而预流推进算法代码量比较大,经常达到200+行,但运行效率略高

为了便于理解,先引入一个引理:最大流最小割定理
在一个连通图中,如果删掉若干条边,使图不联通,则称这些边为此图的一个割集。在这些割集中流量和最小的一个称为最小割
最大流最小割定理:一个图的最大流等于最小割。
大开脑洞一下,发现此结论显而易见,故略去证明(其实严格的证明反而不太好写,但是很容易看出结论是对的,是吧)。这便是增广路算法的理论基础。
在图上从s到t引一条路径,给路径输入流flow,如果此flow使得该路径上某条边容量饱和,则称此路径为一条增广路。增广路算法的基本思路是在图中不断找增广路并累加在flow中,直到找不到增广路为止,此时的flow即是最大流。可以看出,此算法其实就是在构造最小割。

可以通过matlab中的graphmaxflow求解,调用格式如下:
[MaxFlow, FlowMatrix, Cut] = graphmaxflow(G, SNode, TNode)
[...] = graphmaxflow(G, SNode, TNode, ...'Capacity', CapacityValue, ...)
[...] = graphmaxflow(G, SNode, TNode, ...'Method', MethodValue, ...)
【注意】有的时候K为二维矩阵,即存在不唯一的割集。

给出例子如下:


clc
clear
a = zeros(6);
x = [1,1,2,2,3,3,4,5,5];
y = [2,4,3,4,4,6,5,3,6];
w = [8,7,9,5,2,5,9,6,10];
z = sparse(x,y,w,6,6);
h = view(biograph(z,[],'ShowWeights','on'));
[M,F,K] = graphmaxflow(z,1,6)
view(biograph(F,[],'ShowWeights','on'))
set(h.Nodes(K(1,:)),'Color',[1 0 0])
>>
M =

    14


F =

   (1,2)        8
   (2,3)        5
   (1,4)        6
   (2,4)        3
   (4,5)        9
   (3,6)        5
   (5,6)        9


K =

  1×6 logical 数组

   1   1   1   1   0   0

5. 最小费用最大流问题

最小费用最大流是解决这么一种问题: 对于图中的每一条边来说, 除了有一个最大容量的属性以外,还有一个费用属性, 即流过这条边的单位流量的花费。求解的问题为在保证从源点到汇点的流量最大的前提下使得花费最少。




【例】


下面自己编写mincostmaxflow函数(matlab中无工具箱可以调用):

%最小费用最大流函数 

function[flow,val]=mincostmaxflow(rongliang,cost,flowvalue); 

%第一个参数:容量矩阵;第二个参数:费用矩阵; 

%前两个参数必须在不通路处置零 

%第三个参数:指定容量值(可以不写,表示求最小费用最大流) 

%返回值 flow 为可行流矩阵,val 为最小费用值 

global M 

flow=zeros(size(rongliang));allflow=sum(flow(1,:));

if nargin<3 

   flowvalue=M; 

end 

while allflow<flowvalue 

   w=(flow<rongliang).*cost-((flow>0).*cost)'; 

   path=floydpath(w);%调用 floydpath 函数

   if isempty(path) 

       val=sum(sum(flow.*cost)); 

       return; 

   end 

   theta=min(min(path.*(rongliang-flow)+(path.*(rongliang-flow)==0).*M)); 

   theta=min([min(path'.*flow+(path'.*flow==0).*M),theta]); 

   flow=flow+(rongliang>0).*(path-path').*theta; 

   allflow=sum(flow(1,:)); 

end 

val=sum(sum(flow.*cost));

其中用到floydpath函数求最短路径:

%求最短路径函数 

function path=floydpath(w); 

global M num 

w=w+((w==0)-eye(num))*M; 

p=zeros(num); 

for k=1:num 

  for i=1:num 

     for j=1:num 

        if w(i,j)>w(i,k)+w(k,j) 

           w(i,j)=w(i,k)+w(k,j); 

           p(i,j)=k; 

        end 

     end 

  end 

end 

if w(1,num) ==M 

   path=[]; 

else 

   path=zeros(num); 

   s=1;t=num;m=p(s,t); 

   while ~isempty(m) 

       if m(1) 

           s=[s,m(1)];t=[t,t(1)];t(1)=m(1); 

           m(1)=[];m=[p(s(1),t(1)),m,p(s(end),t(end))]; 

       else 

           path(s(1),t(1))=1;s(1)=[];m(1)=[];t(1)=[]; 

       end 

   end 

end 

最后编写求解函数:

function mainexample19 

clear;clc; 

global M num 

c=zeros(6);u=zeros(6); 

c(1,2)=2;c(1,4)=8;c(2,3)=2;c(2,4)=5; 

c(3,4)=1;c(3,6)=6;c(4,5)=3;c(5,3)=4;c(5,6)=7;

u(1,2)=8;u(1,4)=7;u(2,3)=9;u(2,4)=5; 

u(3,4)=2;u(3,6)=5;u(4,5)=9;u(5,3)=6;u(5,6)=10;

num=size(u,1);M=sum(sum(u))*num^2; 

[f,val]=mincostmaxflow(u,c) 
>>
f =

     0     8     0     6     0     0
     0     0     7     1     0     0
     0     0     0     2     0     5
     0     0     0     0     9     0
     0     0     0     0     0     9
     0     0     0     0     0     0


val =

   205

6. matlab 图论工具箱

命令名 功能
graphallshortestpaths 求图中所有顶点对之间的最短距离
graphconncomp 找无向图的连通分支,或有向图的强弱连通分支
graphisdag 测试有向图是否含有圈,不含圈返回1,否则返回0
graphisomorphism 确定两个图是否同构,同构返回1,否则返回0
graphisspantree 确定一个图是否是生成树,是返回1,否则返回0
graphmaxflow 计算有向图的最大流
graphminspantree 在图中找最小生成树
graphpred2path 把前驱顶点序列变成路径的顶点序列
graphshortestpath 求图中指定的一对顶点间的最短距离和最短路径
graphtopootder 执行有向无圈图的拓扑排序
graphtraverse 求从一顶点出发,所能遍历图中的顶点

给出例子如下:

【例】用matlab求解从Node1到Node11的最短路径及长度


clc, clear
a(1,2)=2;a(1,3)=8;a(1,4)=1;
a(2,3)=1;a(2,3)=6;a(2,5)=1;
a(3,4)=7;a(3,5)=5;a(3,6)=1;a(3,7)=2;
a(4,7)=9;
a(5,6)=3;a(5,8)=2;a(5,9)=9;
a(6,7)=4;a(6,9)=6;
a(7,9)=3;a(7,10)=1;
a(8,9)=7;a(8,11)=9;
a(9,10)=1;a(9,11)=2;
a(10,11)=4;
a=a';   %matlab工具箱要求数据是下三角矩阵
[i,j,v]=find(a);
b=sparse(i,j,v,11,11) %构造稀疏矩阵
[x,y,z]=graphshortestpath(b,1,11,'Directed',false) % Directed是标志图为有向或无向的属性,该图是无向图,对应的属性值为false,或0。
h = view(biograph(b,[],'ShowArrows','off','ShowWeights','on'))
set(h.Nodes(y),'Color',[1 0.4 0.4])
 fowEdges = getedgesbynodeid(h,get(h.Nodes(y),'ID'));
 revEdges = getedgesbynodeid(h,get(h.Nodes(fliplr(y)),'ID'));
 edges = [fowEdges;revEdges];
 set(edges,'LineColor',[1 0 0])
 set(edges,'LineWidth',1.5)

>>
x =

    13


y =

     1     2     5     6     3     7    10     9    11


z =

     0     1     6     1     2     5     3     5    10     7     9

得到最短路线如下:


【说明】

  1. find函数可以返回元素的横纵坐标,以及值
  2. 记得变成下三角行列式
  3. sparse函数创造系数矩阵,只记录矩阵中非零元素的左边以及值
  4. graphshortestpath的第一个参数代表最短路程,第二个参数为途中的标号即最短路径是13,最短路径为1-2-5-6-3-7-10-9-11

7. 计划评审法和关键路线法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容

  • 1. 图的定义和基本术语 线性结构中,元素仅有线性关系,每个元素只有一个直接前驱和直接后继;树形结构中,数据元素(...
    yinxmm阅读 5,440评论 0 3
  • 图的定义与术语 1、图按照有无方向分为无向图和有向图。无向图由顶点和边构成,有向图由顶点和弧构成。弧有弧尾和弧头之...
    unravelW阅读 402评论 0 0
  • 主要知识点 图的概述 图的存储结构 图的遍历 最小生成树 最短路径 拓扑排序 关键路径 一、图的概念 图的定义: ...
    JiaJianHuang阅读 1,705评论 0 0
  • 图的基本概念 图由结点的有穷集合V和边的集合E组成。图中常常将结点成为顶点,边是顶点的有序偶对。若两个顶点之间存在...
    桔子满地阅读 1,383评论 0 0
  • 他缓慢的走着 步履蹒跚 一句 回来了啊 平静的脸庞遮不住那颤抖的音嗓 忽然转身 然而还是看到了他眼角含包的泪 走吧...
    野浪花阅读 378评论 0 1