Skip to content

Commit

Permalink
docs: OR
Browse files Browse the repository at this point in the history
  • Loading branch information
Phil-Fan committed May 31, 2024
1 parent a84d970 commit 0a1dbfe
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 9 deletions.
240 changes: 238 additions & 2 deletions docs/CS/DataStructure-Graph.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# 图论 | Graph Theory



<img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531210914839.png" alt="image-20240531210914839" style="zoom:50%;" />

## 基本概念和建模

图论是数学的一个分支,主要研究图这种数据结构。图论中的基础概念主要包括:

1. **图(Graph)**:图是由顶点(Vertex)和边(Edge)组成的数据结构,用于表示对象之间的关系。图通常表示为 G = (V, E),其中 V 是顶点集合,E 是边集合。

2. **顶点(Vertex)**:图中的每个元素称为顶点或节点,表示问题中的一个对象或实体。

3. **边(Edge)**:边表示图中顶点之间的连接关系,可以是有向的(表示方向)或无向的(不表示方向)。

4. **有向图(Directed Graph)**:边具有方向的图称为有向图,也称为网络图。

5. **无向图(Undirected Graph)**:边没有方向的图称为无向图。

6. **权重(Weight)**:图中的边可以具有权重,表示连接两个顶点的成本或距离。

7. **路径(Path)**:图中从一个顶点到另一个顶点的边的序列称为路径。

8. **连通性(Connectivity)**:图中任意两个顶点之间是否存在路径,如果存在,则图是连通的。

9. **环(Cycle)**:图中从一个顶点出发,经过一系列边后又回到该顶点的路径称为环。

10. **子图(Subgraph)**:由原图中部分顶点和连接这些顶点的边组成的图称为子图。





## 表示方法

### 邻接表和邻接矩阵
Expand Down Expand Up @@ -42,12 +74,40 @@
![最短路算法比较](https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240116141856812.png)

### Floyd
### Floyd - 多源最短路

常数小,复杂度高



依次将每个点作为中间点进行更新。

邻接矩阵实现,D数组记录最短路径,Path数据记录终点的前一个点

[图-最短路径-Floyd(弗洛伊德)算法](https://www.bilibili.com/video/BV19k4y1Q7Gj)

### Floyd 算法数学描述

设 G = (V, E) 是一个带权有向图,其中 V 是顶点集合,E 是边集合,w(u, v) 表示从顶点 u 到顶点 v 的权重。Floyd 算法的数学描述如下:

1. 初始化$ D[i][j] = w(i, j)$,如果$ i = j$,则$ D[i][j] = 0$;如果$ (i, j) \in E$,则 $D[i][j] = \infty$。
2. 对于每个$ k \in V$,执行以下操作:
- 对于每个$ i, j \in V$,如果 $D[i][k] + D[k][j] < D[i][j]$,则更新 $D[i][j] = D[i][k] + D[k][j]$。

```c
for (k = 0; k < V; k++) {
for (i = 0; i < V; i++) {
for (j = 0; j < V; j++) {
if (graph[i][k] + graph[k][j] < graph[i][j]) {//能松弛就松弛
graph[i][j] = graph[i][k] + graph[k][j];
}
}
}
}
```





### Dijkstra
Expand All @@ -59,9 +119,14 @@
3. 重复1和2步骤,直到所有点都被标记为已访问的,则`dist[i]``s``i`的最短距离。如果只想求从s到某一点的最短距离,那么当该点被标记为访问过之后可直接退出。
4. 补充:如果除了最短距离之外还想求出具体的路径,只需建立一个`pre`数组,在步骤2后添加操作:`pre[v] = u`(前提是`dist[v]`被更新)。

#### 分析

**最多次数:**最多需要更新<顶点-1>次,将未访问过的点更新成为已经访问过的点;

**限制:**所有边的权值非负

#### 复杂度分析

复杂度分析
$$
正常情况\quad O(n^2)\\
堆优化下 \quad O(n\log n)
Expand Down Expand Up @@ -182,7 +247,178 @@ void bellman(){

## 最大流

### 定义与建模

#### **可行流**

每条弧上给定一个实数$f(u,v)$、,满足$0\le f(u,v)\le c(u,v)$

可行流满足:

- 源点S:流出量 = 整个网络的流量
- 汇点T:流入量 = 整个网络的流量
- 中间的点:总流入量 = 总流出量,同时$0\le f(u,v)\le c(u,v)$​

> 车队送货问题
![在这里插入图片描述](https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/20200729200407863.png)

#### **最大流**

所有可行流中流量最大的流量

![在这里插入图片描述](https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/20200729200443224.png)

#### 饱和

**饱和边/不饱和边**

**反向饱和/不饱和**

![image-20240531214947009](https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531214947009.png)



#### **前向弧\后向弧**

前向弧:与链的方向相同

后向弧:与链的方向相反



#### **增广链**

设f是一个可行流,$\mu$是从发点到收点的一条链,$\mu$满足以下条件时为增广链:

- 若弧$(v_i,v_j)$是前向弧,则$0\le f_{ij} \le c_{ij}$,即$\mu^+$中每一条弧**都要是非饱和弧**

- 若弧$(v_i,v_j)$是后向弧,则$0\le f_{ij} \le c_{ij}$即$\mu^-$​中每一条弧**都要是非零流弧**

!!! note "可行流成为最大流的充分必要条件"
不存在发点到收点的增广链

#### 割集(Cut)

将网络中的点集V分成两个非空集合$V_1$$\bar{V_1}$,使得发点和收点位于两个集合,则弧集$(V_1,\bar{V_1})$是分离发点和收点的割集

> 只要让源和汇不直接相连就可以了,如下图中$(v_1,v_2),(v_3,v_4)$是一个割集
>
> <img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531220934019.png" alt="image-20240531220934019" style="zoom:50%;" />
#### 割量(Cut-set)

对于一个割集 S,割量就是 S 中所有边的容量之和。数学上,割量可以定义为:

$$
Cutset(S) = \sum_{(u, v) \in S} c(u, v)
$$

割量可以用于描述网络流的瓶颈,即网络中限制流量通过的最小容量。在最大流问题中,最小割量等于最大流。

最小割集和最小割量

#### 最大流最小割定理(Max-Flow Min-Cut Theorem)

该定理指出,在任何流网络中,从源点到汇点的最大流等于最小割量。这意味着要找到最大流,可以寻找一个将源点和汇点分开的割集,使得通过该割集的流量最小。

![image-20240531223239298](https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531223239298.png)

用$流量=容量-空闲$,可以得到阻塞流(blocking flow)





### 标号法

**步骤一:**

找出一个可行流(若网络中没有给定初始可行流,可设所有弧的流量 $f_i=0$)。



**步骤二:标号以寻增广链**

(1)发点标号 $\{0,+\infty\}$。

(2)选一个点 $v$ 已标号且另一端点 $u$ 未标号的弧沿着某条链向收点检查。

①若弧为前向弧,且 $f_{ij}<c_{ij}$,则 $u$ 标号 $\{v_i,\theta_j\}$,$\theta_j = c_{ij}-f_{ij}$。

②若弧为后向弧,且 $f_{ji}>0$,则 $u$ 标号 $\{-v_i,\theta_j\}$,$\theta=f_{ji}$。

(3)重复(2),当收点已得到标号,说明找到一条增广链;依据标号点的第一个标号进行反向追踪得到增广链 $u$;若收点不能得到标号,则不存在增广链,算法结束。

**步骤三:调整流量**

(1)求增广链上所有标号点第二个标号的最小值,得到调整量 $\theta=\min\limits_{i=1}^n \theta_i$。

(2)调整流量:增广链上的前向弧 $f_u=f_u+\theta$;增广链上的后向弧 $f_u=f_u-\theta$。

(3)得到新的可行流后,去掉所有有标号,重复步骤二、三,直到收点不能标号为正。

<img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531222016854.png" alt="image-20240531222016854" style="zoom:50%;" />

<img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531222032400.png" alt="image-20240531222032400" style="zoom:50%;" />

<img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531222736954.png" alt="image-20240531222736954" style="zoom:50%;" />



### Ford-Fulkerson 算法

> [【运筹优化】网络最大流问题及三种求解算法详解 + Python代码实现_网络最大流问题例题详解-CSDN博客](https://blog.csdn.net/weixin_51545953/article/details/129009589)
>
> [【运筹学】-图与网络(三)(网络最大流问题)_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1ir4y1S7SA/?spm_id_from=333.337.search-card.all.click&vd_source=8b7a5460b512357b2cf80ce1cefc69f5)
>
> [13-2: Ford-Fulkerson Algorithm 寻找网络最大流_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Pv41157xh/?spm_id_from=333.788&vd_source=8b7a5460b512357b2cf80ce1cefc69f5)
该方法运用贪心的思想,通过寻找增广路来更新并求解最大流;

!!! note "可以反悔,去掉不好的路"
$$
flow = capacity -residual
$$
残存网络其实就是用边的剩余容量来表示每条边,如下图所示的残存网络。S->v2这条边上的数字“2”代表这条边剩余可通过容量为2。

<img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/a727673c41ea4c4c9548a8154aa672d6.png" alt="在这里插入图片描述" style="zoom:33%;" />

该算法概况起来,就是在残存网络中不断寻找增广路径,每找到一条增广路径,就递增最大流 $f$,并更新残存网络,直到残存网络中不存在增广路径,则此时$f$即为最终的最大流。

Ford-Fulkerson 算法是通过 DFS(深度优先遍历)的方式在当前残存网络中寻找增广路径的。

根据木桶原理,增广路径的流量等于该路径的边的最小剩余流量。如下图所示的增广路径,它的流量就是3,因为` v4->t` 的容量为3

<img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/b54c07de6761450d9ec4b72005d42d90.png" alt="在这里插入图片描述" style="zoom:33%;" /><img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/84dee643a7a94f1ba93ed4df2dbe9193.png" alt="在这里插入图片描述" style="zoom:33%;" /><img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/0c094f88a2e144cc9075bc3590500ab7.png" alt="在这里插入图片描述" style="zoom:33%;" />

添加反向边是这一算法能够精确求解最大流问题的基础保障

然后重复上述过程,直到找不到增广路径,算法结束

![在这里插入图片描述](https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/7bdff146857146ad8a75a2d0c494c166.png)

#### 分析

**最大循环次数** 等于最大流,因为最坏情况下每轮循环流量只能增加1

**时间复杂度**:最坏时间复杂度:$O(\mathop{flow}\limits_{max}\times m)$,每一轮需要$O(m)$的时间找到路径



### Edmonds–Karp 算法

### Dinic 算法

## 最小费用流

最小费用最大流问题:在网络$G = (V, E)$上,对每条边给定一个权值$w(u, v)$,称为费用(cost),含义是单位流量通过$ (u, v)$ 所花费的代价。对于$G$所有可能的最大流,我们称其中总费用最小的一者为最小费用最大流。

### SSP 算法

SSP(Successive Shortest Path)算法是一个贪心的算法。它的思路是每次寻找单位费用最小的增广路进行增广,直到图上不存在增广路为止。

如果图上存在单位费用为负的圈,SSP 算法无法正确求出该网络的最小费用最大流。此时需要先使用消圈算法消去图上的负圈。

## 工程进度优化

2 changes: 2 additions & 0 deletions docs/CS/DataStructure-Tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

## 性质

- 无环
- 加上一条边就有环,去掉一条边就不连通
- 节点数 = 所有节点的度数+1
- 度为m的树,第i层至多有$m^{i-1}$个节点
- 最多节点:(等比数列求和)$\frac{m^h - 1}{m-1}$
Expand Down
22 changes: 15 additions & 7 deletions docs/CS/OR-DP.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,32 @@

## 基本概念与建模

1. 阶段
2. 状态
3. 决策和策略
4. 状态转移方程
5. 指标函数
1. **阶段**:问题过程按时间、空间的特征分解成若干相互联系的阶段。
2. **状态**:k阶段开始(或结束)时的客观条件,记为$s_k \in S_k$,$S_k$为$k$阶段状态集合
3. **决策**:依据状态做出的决定,记为$u_k(s_k)\in D_k(s_k)$ , $Dk (sk)$为状态$s_k$的允许决策集合。<img src="https://philfan-pic.oss-cn-beijing.aliyuncs.com/img/image-20240531194223986.png" alt="image-20240531194223986" style="zoom:67%;" />如$D_1(A) = {B_1,B_2,B_3},u_1(A) = B_i \quad i = 1,2,3$
4. **状态转移方程:**描述当前状态在给定决策下转移至下一阶段的过程;$s_{k+1}=T_k(s_k, u_k (s_k))$
5. **指标函数**:评价沿子策略$P_{k,n}$过程性能优劣的函数,记为$V_{k,n}(s_{k}, p_{k,n})$。


## 基本原理与求解

**状态的无后效性:**已经求解的子问题,不会再受到后续决策的影响。

后部子过程策略,从k阶段开始到终了阶段的决策子序列,记为$p_{s,n}(s_k) = \{u_k \left(s_k\right), u_{k+1}\left(s_{k+1}\right),\dots, u_n\left(s_n\right)\} \in P_{k,n} (s_k)$

最优化原理: 最优策略的子策略是对应子问题的最优策略。

最优化定理:策略$p^*_{l,n}$是最优策略的充要条件是,对于所有的k,都有:
$$
\begin{array}{l}
V_{1,n}\left({s_{1}}, p_{1, n}^{*}\right) \\
\quad=\mathop{opt}\limits_{p_{1, k-1} \in p_{1, k-1}} V_{1, k-1}\left(s_{1}, p_{1, k-1}\right)+\mathop{opt}\limits_{p_{k, n} \in p_{k, n}} V_{k, n}\left(s_{k}, p_{k, n}\right)
V_{1,n}\left({s_{l}}, p_{1, n}^{*}\right) \\
\quad=\mathop{opt}\limits_{p_{l, k-1} \in p_{l, k-1}} V_{1, k-1}\left(s_{1}, p_{1, k-1}\right)+\mathop{opt}\limits_{p_{k, n} \in p_{k, n}} V_{k, n}\left(s_{k}, p_{k, n}\right)
\end{array}
$$

> 新的最短路节点必定从已知的最短路节点展开


顺序解法和逆序解法无本质区别
若初始状态给定时,用逆序解法比较简单。
Expand Down

0 comments on commit 0a1dbfe

Please sign in to comment.