图与网络03—最小生成树

图与网络03—最小生成树

第三篇图与网络的学习笔记,同最短路问题一样,都是图论中的经典之经典——“最小生成树”!!!
还是把握两个大方向:“数学+代码”,冲!!!



前言

咕咕咕~~~

一、基本概念和算法

1. 数值矩阵的建立

(tree)是图论中非常重要的一类图,它非常类似于自然界中的树,结构简单、应用广泛,最小生成树问题则是其中的经典问题之一。在实际应用中,许多问题的图论模型都是最小生成树,如通信网络建设有线电缆铺设加工设备分组等。

【定义 3.1】 连通的无圈图称为树。
例如,下图给出的 是树,但 G 1 G1 G1 G 2 G2 G2则不是树。
在这里插入图片描述
【定理3.1】 G G G是具有 n n n个顶点 m m m条边的图,则以下命题等价。
(1)图 G G G是树;
(2)图 G G G中任意两个不同顶点之间存在唯一的路。
(3)图 G G G连通,删除任一条边均不连通;
(4)图 G G G连通,且 n = m + 1 n=m+1 n=m+1
(5)图 G G G无圈,添加任一条边可得唯一的圈;
(6)图 G G G无圈,且 n = m + 1 n=m+1 n=m+1

【定义3.2】 若图 G G G的生成子图 H H H是树,则称 H H H G G G的生成树或支撑树。
一个图的生成树通常不唯一。

【定理3.2】 连通图的生成树一定存在。
方法:破圈法

【证明】
给定连通图 G G G,若 G G G无圈,则 G G G本身就是自己的生成树。若 G G G有圈,则任取 G G G中一个圈 C C C,记删除 C C C中一条边后所得之图为 G ′ G' G。显然 G ′ G' G中圈 C C C已经不存在,但 G ′ G' G仍然连通。若 G ′ G' G中还有圈,再重复以上过程,直至得到一个无圈的连通图 H H H。易知 H H H G G G的生成树。

【定义3.3】 在赋权图 G G G中,边权之和最小的生成树称为 G G G的最小生成树。
n n n个顶点的完全图,其不同的生成树的个数为 n n − 2 n^{n-2} nn2
不能枚举

对于赋权图 G = ( V , E , W ) G=(V,E,W) G=(V,E,W),其中 V V V为顶点集合, E E E为边的集合, W W W为邻接矩阵,这里顶点集合 V V V中有 n n n个顶点,下面构成它的最小生成树——所有生成树中所有边上权重和最小的生成树。

2. Kruskal算法(克鲁斯卡尔算法)

Kruskal算法思想——每次将一条权最小的边加入子图 T T T中,并保证不形成圈。
方法:避圈法

Kruskal算法如下
(1) e 1 ∈ E e_1∈E e1E,使得 e 1 e_1 e1是权值最小的边。
(2) e 1 , e 2 , ⋯ , e i e_1,e_2,⋯,e_i e1,e2,,ei已选好,则从 E − e 1 , e 2 , ⋯ , e i E-{e_1,e_2,⋯,e_i} Ee1,e2,,ei中选取 ,使得
e 1 , e 2 , ⋯ , e i , e i + 1 {e_1,e_2,⋯,e_i,e_{i+1}} e1,e2,,ei,ei+1中无圈,且
e i + 1 e_{i+1} ei+1 E − e 1 , e 2 , ⋯ , e i E-{e_1,e_2,⋯,e_i} Ee1,e2,,ei中权值最小的边。
(3) 直到选得 e n − 1 e_{n-1} en1为止。

3. Prim算法(普里姆算法)

集合 P P P存放 G G G的最小生成树中的顶点
集合 Q Q Q存放 G G G的最小生成树中的边
令集合 P P P的初值为 P = v 1 P={v_1} P=v1(假设构造最小生成树时,从顶点 v 1 v_1 v1出发),集合 Q Q Q的初值为 Q = Φ Q=Φ Q=Φ(空集)。

Prim算法的思想——从所有 p ∈ P p∈P pP v ∈ V − P v∈V-P vVP的边中,选取具有最小权值的边 p v pv pv,将顶点 v v v加入集合 P P P中,将边 p v pv pv加入集合 Q Q Q中,如此不断重复,直到 P = V P=V P=V时,最小生成树构造完毕,这时集合 Q Q Q中包含了最小生成树的所有边。

Prim算法如下
(1) P = v 1 P={v_1} P=v1 Q = Φ Q=Φ Q=Φ
(2) w h i l e P   = V while P~=V whileP =V
\qquad 找最小边 p v pv pv,其中 p ∈ P , v ∈ V − P p∈P,v∈V-P pP,vVP
P = P + v \qquad P=P+{v} P=P+v
Q = Q + p v \qquad Q=Q+{pv} Q=Q+pv
e n d \qquad end end

【例3.1】 一个乡有9个自然村,其间道路及各道路长度如图4.11所示,各边上的数字表示距离,问架设通信线时,如何拉线才能使用线最短。
在这里插入图片描述

【解】 这就是一个最小生成树的问题,用Kruskal算法求解。先将边按大小顺序由小至大排列:
在这里插入图片描述
然后按照边的顺序排列,取定:
在这里插入图片描述
取边原则——先小后大,避圈

由于下一个未选中的最小权边 ( v 0 , v 3 ) (v_0,v_3) (v0,v3)与已选边 e 1 , e 2 e_1,e_2 e1,e2构成圈,所以排除,选 e 8 = ( v 6 , v 7 ) e_8=(v_6,v_7) e8=(v6,v7),得到下图,就是图 G G G的一棵最小生成树,它的权是13。
在这里插入图片描述
基于邻接矩阵构成图的MATLAB程序如下:

clc, clear, close all, a=zeros(9);
a(1,[2:9])=[2 1 3 4 4 2 5 4];
a(2,[3 9])=[4 1]; a(3,4)=1; a(4,5)=1;
a(5,6)=5; a(6,7)=2; a(7,8)=3; a(8,9)=5;
s=cellstr(strcat('v',int2str([0:8]')));
G=graph(a,s,'upper'); p=plot(G,'EdgeLabel',G.Edges.Weight);
T=minspantree(G,'Method','sparse') %Kruskal算法
L=sum(T.Edges.Weight), highlight(p,T)

基于边的细胞数组构造图的MATLAB程序如下:

clc, clear, close all
nod =cellstr(strcat('v',int2str([0:8]')));
G = graph; G = addnode(G,nod);
ed ={ 'v0','v1',2;'v0','v2',1;'v0','v3',3;'v0','v4',4
    'v0','v5',4;'v0','v6',2;'v0','v7',5;'v0','v8',4
    'v1','v2',4;'v1','v8',1;'v2','v3',1;'v3','v4',1
    'v4','v5',5;'v5','v6',2;'v6','v7',3;'v7','v8',5};
G = addedge(G,ed(:,1),ed(:,2),cell2mat(ed(:,3))); 
p=plot(G,'EdgeLabel',G.Edges.Weight);
T=minspantree(G), L=sum(T.Edges.Weight)
highlight(p,T)

代码效果:
在这里插入图片描述


二、最小生成树的数学规划模型

顶点 v 1 v_1 v1表示树根,总共有 n n n个顶点。顶点 v i v_i vi到顶点 v j v_j vj边的权重用 w i j w_{ij} wij表示,当两个顶点之间没有边时,对应的权重用 M M M(充分大的正实数)表示,这里 w i i = M , i = 1 , 2 , ⋯ , n w_ii=M,i=1,2,⋯,n wii=M,i=1,2,,n
引入0-1变量
x i j = { 1 当 从 v i 到 v j 的 边 在 树 中 0 , 当 从 v i 到 v j 的 边 不 在 树 中 x_{ij}= \begin{cases} 1 & 当从v_i到v_j的边在树中 \\ 0, & 当从v_i到v_j的边不在树中 \\ \end{cases} xij={10,vivjvivj
目标函数是使得 z = ∑ i = 0 n ∑ j = 0 n w i j x i j z =\sum_{i=0}^n {\sum_{j=0}^n {w_{ij}x_{ij}}} z=i=0nj=0nwijxij最小化
约束条件分成如下4类:
(1)根v_1至少有一条边连接到其他的顶点,
∑ j = 0 n x 1 j = 1 \sum_{j=0}^n {x_{1j}}=1 j=0nx1j=1

(2)除根外,每个顶点只能有一条边进入,
∑ i = 0 n x i j = 1 , j = 2 , . . . , n . \sum_{i=0}^n {x_{ij}}=1,j=2,...,n. i=0nxij=1,j=2,...,n.

以上两约束条件是必要的但非充分的
可保证边数为顶点个数-1,但不能保证无圈

需要增加一组变量 u j ( j = 1 , 2 , ⋯ , n ) u_j (j=1,2,⋯,n) uj(j=1,2,,n),再附加约束条件:

(3)限制 u j u_j uj的取值范围为:
u 1 = 0 ,   1 ≤ u i ≤ n − 1 ,   i = 2 , 3 , ⋯ , n u_1=0, 1≤u_i≤n-1, i=2,3,⋯,n u1=0,1uin1,i=2,3,,n.

(4)各条边不构成子圈,
u i − u j + n x i j ≤ n − 1 ,   i = 1 , ⋯ , n , j = 2 , ⋯ , n . u_i-u_j+nx_{ij}≤n-1, i=1,⋯,n,j=2,⋯,n. uiuj+nxijn1,i=1,,n,j=2,,n.

最小生成树的0-1帧数规划问题模型如下:
z = ∑ i = 0 n ∑ j = 0 n w i j x i j ′ z =\sum_{i=0}^n {\sum_{j=0}^n {w_{ij}x'_{ij}}} z=i=0nj=0nwijxij
s . t . { ∑ j = 0 n x 1 j = 1 ∑ i = 0 n x i j = 1 j = 2 , . . . , n . u 1 = 0 ,   1 ≤ u i ≤ n − 1 ,   i = 2 , 3 , ⋯ , n . u i − u j + n x i j ≤ n − 1 ,   i = 1 , ⋯ , n , j = 2 , ⋯ , n . x i j = 0 或 1 , i , j = 1 , 2 , . . . , n . s.t. \begin{cases} \sum_{j=0}^n {x_{1j}}=1\\ \sum_{i=0}^n {x_{ij}}=1 &j=2,...,n. \\ u_1=0, 1≤u_i≤n-1, &i=2,3,⋯,n. \\ u_i-u_j+nx_{ij}≤n-1, &i=1,⋯,n,j=2,⋯,n. \\ x_{ij}=0或1,&i,j=1,2,...,n. \\ \end{cases} s.t.j=0nx1j=1i=0nxij=1u1=0,1uin1,uiuj+nxijn1,xij=01j=2,...,n.i=2,3,,n.i=1,,n,j=2,,n.i,j=1,2,...,n.

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

【例3.2】 利用数学规划模型求解例4.12。一个乡有9个自然村,其间道路及各道路长度如图4.11所示,各边上的数字表示距离,问架设通信线时,如何拉线才能使用线最短。
在这里插入图片描述

clc, clear, close all, n = 9;
nod =cellstr(strcat('v',int2str([0:n-1]')));
G = graph(); G = addnode(G,nod);
ed ={ 'v0','v1',2;'v0','v2',1;'v0','v3',3;'v0','v4',4
    'v0','v5',4;'v0','v6',2;'v0','v7',5;'v0','v8',4
    'v1','v2',4;'v1','v8',1;'v2','v3',1;'v3','v4',1
    'v4','v5',5;'v5','v6',2;'v6','v7',3;'v7','v8',5};
G = addedge(G,ed(:,1),ed(:,2),cell2mat(ed(:,3))); 
w = full(adjacency(G,'weighted'));
w(w==0) = 1000000; %这里1000000表示充分大的正实数
prob = optimproblem;
x = optimvar('x',n,n,'Type','integer','LowerBound',0,'UpperBound',1);
u = optimvar('u',n,'LowerBound',0);
prob.Objective = sum(sum(w.*x));
con1 = [1<=sum(x(1,:)); 1<=u(2:end); u(2:end)<=n-1];
con2 = [sum(x(:,[2:end]))'==1; u(1)==0]; 
con3 = optimconstr(n*(n-1)); k=0;
for i = 1:n
    for j = 2:n
        k=k+1; con3(k) = u(i)-u(j)+n*x(i,j)<=n-1;
    end
end
prob.Constraints.con1 = con1;
prob.Constraints.con2 = con2;
prob.Constraints.con3 = con3;
[sol,fval,flag,out] = solve(prob)
[i,j]=find(sol.x);
ind = [i'; j']  %输出树的顶点编号

代码效果:
在这里插入图片描述


总结

以上就是本文主要内容,从最基础的原理讲图论的基本概念,以及最小生成树的数学模型与如何用MATLAB进行实现。下面我们将进行着色问题和旅行商问题的讨论。
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值