图与网络分析

图的基本概念与模型

P.S. 只列一些陌生概念(为什么图的概念会有这么多版本😅无语住了)

  • :与某一个点 viv_i 相关联的边的数目称为点 viv_i 的次(degree),也叫做 ,记作 d(vi)d(v_i)
  • 部分图G1={V1,E1}G_1 = \left\{ V_1,E_1 \right\}G2={V2,E2}G_2 = \left\{ V_2,E_2 \right\},若有 V1=V2,E1E2V_1 = V_2, E_1 \sqsubseteq E_2,则称 G1G_1G2G_2 的部分图。注意:部分图也是子图,子图不一定是部分图。(子图:V1V2,E1E2V_1 \sqsubseteq V_2, E_1 \sqsubseteq E_2
  • 链、路:图中存在点和边交替序列 μ={v0,e1,v1,,ek,vk}\mu=\left\{ v_0,e_1,v_1,\cdots ,e_k,v_k \right\},若其中各边 e1,e2,eke_1,e_2,\cdots e_k 各不相同,且对任意的 1tk1\le t\le k 有,vt1v_{t-1}vtv_t 相邻,则称 μ\mu。如果链中所有顶点 v0,v1,vkv_0,v_1,\cdots v_k 也互不相同,则称这样的链为

树和图的最小部分树

最小部分树就是最小生成树

树的性质

  • 任何树中必定存在度为 1 的点
  • 具有 n 个顶点的树的边树恰好等于 (n1)(n-1)
  • 任何具有 n 个点、(n-1) 条边的连通图是树

以上性质说明:

  • 树是无圈连通图中边数最多,即在树上只要任意再加上一条边就一定会出现圈。
  • 由于树是无圈的连通图,即图的任意两个点之间有且仅有一条唯一通路。因此树也是最脆弱的连通图,只要从树中取走任意一条边,图就不连通了。因此一些重要的网络不能按照树的结构设计。

图的最小部分树

定义
如果 G1G_1G2G_2 的部分图,同时又是树,则称 G1G_1G2G_2 的部分树。在所有部分树中树枝总长度最小的部分树,称为该图的最小部分树(也称为最小支撑树)。

定理
图中任意一点 i,若 j 是与 i 相邻点中距离最近的,则边 [i,j][i,j] 一定> 含在该图的最小部分树内。

避圈法和破圈法

两种方法寻找图的最小部分树

避圈法:

  1. 从图中任选一点 viv_i,使得 viVv_i \in V,图中其余点均包含在 V\overline{V}
  2. VVV、\overline{V} 的连线中找出最小边,这条边一定包含在最小部分树内。不妨设最小边为 [vi,vj][v_i,v_j],将其加粗,用以标记该边是最小部分树内的边。
  3. Vvi    VV\vi    VV \cup v_i \implies V,\overline{V} \backslash v_i \implies \overline{V}
  4. 重复 2、3 两步,直至图中所有点均包含在 V 中为止。

破圈法:

  • 从网络图 N 中任意取一条回路
  • 去掉这个回路中权数最大的一条边,得到一个子网络 N1N_1.
  • N1N_1 中再任取一回路,再去掉回路中权数最大的一条边,得到 N2N_2
  • 如此继续下去,一直到剩下的子图中不再含回路为止。得到的子图就是 N 的最小部分树。

最短路问题

Dijkstra 算法(求指定两点之间最短距离)

dijd_{ij} 表示图中两相邻点 iijj 的距离,若 iijj 不相邻,令 dij=d_{ij} = \infty,显然 dii=0d_{ii} = 0,若用 LsiL_{si} 表示从 ss 点到 ii 点的最短距离,现要求从 ss 点到某一点 tt 的最短距离,用 DijkstraDijkstra 算法步骤如下:

  1. 从点 ss 出发,因为 Lss=0L_{ss} = 0,将此值标注在 ss 旁的小方框内,表示 ss 点已标号;
  2. ss 点出发,找出与 ss 相邻的点中距离最小的一个,设为 rr,将 Lsr=Lss+dsrL_{sr} = L_{ss} + d_{sr} 的值标注在 rr 旁的小方框内,表明点 rr 也已经标号;
  3. 从已标号的点出发,找出与这些点相邻的所有未标号的点 pp,若有 Lsp=min(Lss+dsp;Lsr+drp)L_{sp} = \min(L_{ss}+d_{sp}; L_{sr} + d_{rp}),则对 pp 点标号,并将 LspL_{sp} 的值标注在 pp 点旁的小方框内;
  4. 重复前三步骤,一直到 tt 点得到标号为止

Floyd 算法(求任意两点之间的最短距离)

要点:以每一个顶点为中转站,刷新所有入度和出度的距离
因此需要:遍历每一个点顶点 --> 遍历每一个顶点的入度 --> 遍历每一个顶点的出度,以这个点为中转站,距离更短就刷新距离
核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for (int i = 0; i < graph.length; i++) {
//所有入度
for (int j = 0; j < graph.length; j++) {
//所有出度
for (int k = 0; k < graph[j].length; k++) {
//以每个点为「中转」,刷新所有出度和入度之间的距离
//例如 AB + BC < AC 就刷新距离
if (graph[j][i] != -1 && graph[i][k] != -1) {
int newDistance = graph[j][i] + graph[i][k];
if (newDistance < graph[j][k] || graph[j][k] == -1) {
//刷新距离
graph[j][k] = newDistance;
//刷新路径
path[j][k] = i;
}
}
}
}
}

网络的最大流

相关概念

有向图与容量网络
研究流量问题时候常常在有向图中进行。有向图上的有规定指向的连线称作 。弧的代号是 (vi,vj)(v_i,v_j), 有向图是点与弧的集合,记作 D(V,A)D(V,A)
容量网络是指每条弧 (vi,vj)(v_i,v_j) 都给出一个最大的通过能力,称为该弧的容量,记为 c(vi,vj)c(v_i,v_j) 或简写成 cijc_{ij}。容量网路中规定一个发点(也称为源点,记作 ss)和一个收点(也称汇点,记作 tt),其他点称为中间点。
网络的最大流是指网络中从发点到收点之间允许通过的最大流量

流与可行流
所谓流是指加在网络上各条弧上的一组负载量。对加在弧 (vi,vj)(v_i,v_j) 上的负载量记作 f(vi,vj)f(v_i,v_j) 或简写成 fijf_{ij}。若网络上所有的 fij=0f_{ij}=0,这个流成为零流。
称在容量网络上满足条件 (1.1)(1.2)(1. 1)、(1. 2) 的一组流为可行流

  1. 容量限制条件,对所有弧有

0f(vi,vj)c(vi,vj)(1. 1)0\le f(v_i,v_j) \le c(v_i,v_j)\tag{1. 1}

  1. 中间点平衡条件

f(vi,vj)f(vj,vi)=0(is,t)(1. 2)\sum_{}f(v_i,v_j) - \sum_{}f(v_j,v_i) = 0\quad (i \neq s,t) \tag{1. 2}

若以 v(f)v(f) 表示网络中 sts\to t 的流量,则有

v(f)=jf(vs,vj)+jf(vj,vt)(1. 3)v(f) = \sum_{j}f(v_s,v_j) + \sum_{j}f(v_j,v_t) \tag{1. 3}

任何网络一定存在可行流,因零流是可行流。求网络最大流是指,满足容量限制条件和中间点平衡条件下,使 f(v)f(v) 值达到最大。

割和流量

是指将容量网络中的发点和收点分割开,并使 sts\to t 的流中断的一组弧的集合,

最大流最小割定理

增广链
如果在网络的发点和收点之间能找出一条链,在这条链上所有指向为 sts \to t 的弧(称 前向弧,记作 μ+\mu^{+}),存在 f<cf<c;所有指向为 tst \to s 的弧(称 后向弧,记作 μ\mu^{-}),存在 f>0f>0,这样的链称 增广链
当有增广链存在时找出

θ=min{(cifi),μ+fi ,  对μ(θ>0)\theta = \min \begin{cases} (c_i-f_i),\quad \text{对} \mu^{+} \\ f_i\ ,\quad \quad \quad \ \ \text{对} \mu^{-} \end{cases} \qquad (\theta > 0)

再令

f={fi+θ,对所有μ+fiθ,对所有μfi ,  对非增广链上的弧f^{'} = \begin{cases} f_i + \theta,\quad \text{对所有} \mu^{+} \\ f_i - \theta,\quad \text{对所有} \mu^{-} \\ f_i\ , \quad \quad\ \ \text{对非增广链上的弧} \end{cases}

显然 ff^{'} 仍是一个可行流,但较之原来的可行流 ff,这时网络中从 sts \to t 的流量增大了一个 θ\theta,因此 只有当网络图中找不到增广链时,sts \to t 的流才不可能进一步增大

定理:
在网络中 sts \to t 的最大流量等于它的最小割集的容量,即

v(f)=c(V,V)v^{*}(f) = c^{*}(V,\overline{V})

求网络最大流的标号算法

又称 FordFulkersonFord-Fulkerson 标号算法
算法实质是判断是否有增广链存在 并设法吧增广链找出来
标号算法步骤:

  1. 首先给发点 ss 标号 (0,ε(s))(0,\varepsilon(s))。括弧中第一个数字是使这个点得到标号的前一个点的标号,因 ss 是发点,故记作 00;第二个数字 ε(s)\varepsilon(s) 表示从上一个标号点到这个标号点的流量最大允许调整值,ss 为发点,不限允许调整量,故 ε(s)=\varepsilon(s) = \infty
  2. 列出与已标号点相邻的所有未标号点:
    1. 考虑从标号点 ii 出发的弧 (i,j)(i,j),如果有 fij=cijf_{ij} = c_{ij},不给点 jj 标号;若有 fij<cijf_{ij} < c_{ij},则对点 jj 标号,记为 (i,ε(j))(i,\varepsilon(j)),括弧中 ii 表示点 jj 的标号是从点 ii 延伸过来的,ε(j)=min{ε(i),(cijfij)}\varepsilon(j) = min \{ \varepsilon(i),(c_{ij}-f_{ij})\}
    2. 考虑所有指向标号点 ii 的弧 (h,i)(h,i),如果有 fhi=0f_{hi}=0,对 hh 点不标号;若有 fhi>0f_{hi} > 0,则对点 hh 标号,记为 (h,ε(h))(h,\varepsilon(h)),其中,ε(h)=min{ε(h),fhi}\varepsilon(h) = min \{ \varepsilon(h),f_{hi}\}
    3. 如果某为标号点 kk 有两个以上相邻的标号点,为了减少迭代次数,可按前两步中所述规则分别计算出 ε(k)\varepsilon(k) 的值,并取其中最大的一个标记。
  3. 重复第2步,可能出现以下两种结局:
    • 标号过程中断,tt 得不到标号,说明该网络中不存在增广链,给定的流量即为最大流。记已标号点的集合为 VV,未标号点集合为 V\overline{V}(V,V)(V,\overline{V}),为网络的最小割;
    • tt 得到标号,这时可用反向追踪法在网络中找出一条从 sts \to t 的由标号点及相应的弧连接而成的增广链。
  4. 修改流量,设图中原有可行流为 ff,令

    f={f+ε(t),对增广链上所有前向弧fε(t),对增广链上所有后向弧f ,  对所有非增广链上的弧f^{'}= \begin{cases} f + \varepsilon(t),\quad \text{对增广链上所有前向弧} \\ f - \varepsilon(t),\quad \text{对增广链上所有后向弧} \\ f\ , \quad \quad \quad \ \ \text{对所有非增广链上的弧} \end{cases}

    这样又得到网络上的一个新的可行流 ff^{'}.
  5. 抹掉图上所有标号,重复一至四步,直至图中找不到任何增广链,即出现第三步的第一个结局为止,这是网络图中的流量即为最大流。

最小费用流

最小费用流问题描述:
设网络有 nn 个点,fijf_{ij} 为弧 (i,j)(i,j) 上的流量,cijc_{ij} 为该弧的容量,bijb_{ij} 为在弧 (i,j)(i,j) 上通过单位流量时的费用,sis_i 代表第 ii 点的可供量或需求量,当 ii 为发点时,si>0s_i>0ii 为收点时,si<0s_i<0ii 为中转点时,si=0s_i=0。当网络供需平衡,即 isi=0\displaystyle \sum_{i}s_i=0 时,将各发点物资调运到各收点(或从各发点按最大流量调运到各收点),使总掉运费用最小的问题,可归结为如下线性规划模型:

min z=i=1nj=1nbijfijs.t.{j=1nfijk=1nfki=si(i=1,,n)0fijcij(对弧(i,j))min\ z = \sum_{i=1}^{n}\sum_{j=1}^{n}b_{ij}\,f_{ij} \\ s.t. \begin{cases} \displaystyle \sum_{j=1}^{n}f_{ij} - \sum_{k=1}^{n}f_{ki} = s_i(i=1,\cdots ,n) \\ 0 \le f_{ij} \le c_{ij} (对弧(i,j)) \\ \end{cases}

最小费用流问题解题步:

  1. 从零流 f0f_0 开始。f0f_0 是可行流,也是相应的流量为零时费用最小的
  2. 对可行流 fkf_k 构造加权网络 W(fk)W(f_k),方法是:
    1. 0<fij<cij0<f_{ij}<c_{ij} 的弧 (i,j)(i,j),当其为正向弧时,通过单位流的费用为 bijb_{ij},当其为反向弧时,相应费用 bji=bijb_{ji}=-b_{ij}。故在 iijj 点之间分别给出弧 (i,j)(i,j)(j,i)(j,i) ,其权数分别为 bijb_{ij}bij-b_{ij}
    2. fij=cijf_{ij}=c_{ij} 的弧 (i,j)(i,j),因为该弧流量已饱和,在增广链中只能作为反向弧。故在 W(jk)W(j_k) 中只画出弧 (j,i)(j,i),其权数值为 bij-b_{ij}
    3. fij=0f_{ij} = 0 的弧 (i,j)(i,j),在增广链中只能为正向弧,故在 W(jk)W(j_k) 中只画出弧 (i,j)(i,j),其权数值为 bijb_{ij}
  3. 在加权网络 W(fk)W(f_k) 中,寻找费用最小的增广链,也即求从 sts \to t 的最短路,并将该增广链上流量调整至允许的最大值,得到一个新的流量 fk+1(>fk)f_{k+1}(>f_k)
  4. 重复第二、三两步,直至网络 W(fk+m)W(f_{k+m}) 中找不到增广链(也即找不出最短路)时,fk+f_{k+} 即为要寻找的最小费用流。