课程简介图的基本概念图的概念Ramsey 定理代数表示道路与回路道路与回路欧拉回路哈密顿道路树定义Huffman树最短树KruskalPrim匹配二分图匹配完全匹配二分图最大匹配的König定理网络流jyy 的引入:求不相交路径个数最大流最小割定理E-K 算法Dinic 算法平面图转对偶图最小费用最大流习题2.12.22.32.42.52.72.172.212.252.296.216.4006-1210-七
离散数学 研究对象:离散个体以及结构关系
图论与代数结构 的书还讨论了 平面图与图的着色、图的匹配问题、网络流、抽象代数的内容
主要复习:
图的基本概念
有向图的度=入度+出度
支撑子图/生成子图 v.s. 导出子图;
图的代数表示:What's 关联矩阵(
证明方法:反证法,数学归纳法,直接证明构造法。
含有
道路与回路
道路可以表示为
如果
区别欧拉回路(每条边经过一遍)和哈密顿回路(每个点经过一遍)
完全图哈密顿回路的个数
Peterson 图:存在哈密顿道路而无哈密顿回路;
哈密顿道路判定的结论:
也可以这么证明:取极长回路,一定会包含所有节点,如果不包含
哈密顿回路判定的结论:
不存在哈密顿回路的判定:
可以被画作二分图,而有奇数个节点。可以被画作二分图,但是两个点集的大小不相同。
不存在哈密顿道路的判定:
闭合图:若简单图有不相邻节点
树
Huffman 树:
图
对任一图
图的分类
无限图:节点集或者边集是无穷集合。
有限图:节点集或者边集均是有限集合。我们只讨论有限图。
节点集
边集
无向图:所有的边是无向边:
有向图:所有的边是有向边:
混合图:既有无向边又有有向边。
自环和重边
自环:
重边:两个节点有多条边。
简单图 无自环无重边的无向图。
空图 有点无边的图。
完全图 任意两节点之间都有边的简单图。
节点的度
定义:与节点
握手定理:对于
赋权图
定义:对每条边
子图
定义:给定
如果
如果
记忆:生成子图对节点集有要求,导出子图对边有要求。
图的运算
交
对称差(
图的运算
删点
图的同构
定义:给定图
则
必要条件:
Peterson 图。
对于红色
邻接矩阵 (adjacency matrix)
无向图的邻接矩阵是对称矩阵;无向简单图邻接矩阵的第
权矩阵
关联矩阵 (incidence matrix)
有向图
每列只有两个
第
可以表示重边,不能表示自环。
图的矩阵表示:
矩阵表示法唯一、直观。
不能表示重边或者自环。
需要较大的存储空间。
边列表 对于每条边
正向表 有向图用
从
但是插入删除操作复杂度高。
邻接表
有向道路 有向图
有向回路
道路/链 无向图
一个点可以成为道路,但是不能成为回路。
如果
回路/圈
极长路径/初级道路
扩大初级道路法 求极长路径。
弦 设
联通性
若无向图
对于有向图
若
设
若
二分图
若
充分必要条件:不存在奇环。
证明 必要性,若不存在环,就是一棵树。
如果存在环,则环上的点属于的点集应该是互相间隔的,因此不存在奇环。
证明 充分性,黑白染色。设
若
道路与回路的判定
Warshall 算法,
搜索法、邻接矩阵法。
欧拉:每条路都走一遍。
欧拉回路:连通图
欧拉道路:连通图
欧拉图:具有欧拉回路的图。
欧拉半图:具有欧拉道路但是无欧拉回路的图。
定理:无向 连通图
必要性 每个点的进入次数和出去次数相等。
充分性 当
定理: 无向连通图
证明: 连接这两顶点,则有回路;再删去这条边。
定理:有向连通图
定理:有向连通图
定理:设连通图
证明:增加
哈密顿:每个顶点走一遍。
哈密顿 (H) 回路(道路):无向图
要求
只需考虑简单图,因为重边和自环不起作用。
哈密顿图:具有 H 回路的图。
哈密顿半图:具有 H 道路而无 H 回路的图。
若简单图有
引理: 设
定理:若简单图
首先,
因此矛盾。
其次,我们构造
若
若
重复以上步骤,即可得到
推论:若简单图
则存在
一定存在哈密顿道路
若
若
设
若任意
推论:若简单图
推论:若简单图
则
若
若
这种情况下,如果
闭合图 若
简单表示为,在
若简单图有
若
设
考虑
不能用作判断哈密顿图的条件
但是,可以证明不是哈密顿图:
有割点的连通图不是哈密顿图。
tips: 选择的点集贪心地考虑的话,要考虑度数大的,其次考虑和之前选的点尽量不相邻的。
但是,对于 Peterson 图,都满足这个条件,但是也不是哈密顿图。
奇数个结点构成的二分图不是哈密顿图。
证:否则 H 圈是奇圈,而二部图无奇圈.
树 是不含回路的连通图
树必不含多重边和自环, 故是简单图
边称为树枝
度为1的结点称为树叶(leaf )或悬挂点
度大于等于2的结点称为分叉点
林 是含回路的图
林可能不是连通的
林的每个连通支都是树-
割边 若
树的等价定义
设
树是边数最少的连通图,也是边数最多的无回路图。
满足联通、无回路,
条边中任意两个条件的图是树。
设树
考虑节点度数。
考虑从任意节点
设树
若林
生成树 定义: 如果
图
余树 图
余树不一定连通,也不一定无回路。
余树不一定是树,更不一定是生成树。
二叉树
设
节点的出度最多为 2 的根树称为 二叉树;
除了树叶外,其余结点的出度都是 2,称为 完全二叉树。
一棵高度为
若二叉树的深度为
赋权二叉树
赋予树叶
带权路径总长度:
最优二叉树 给定树叶数目及其权值,构造 WPL 最小的二叉树,称为 Huffman 树。
Huffman 算法:给定
排序得
计算
若
为什么是最优
假定
递推
最优的条件:
由于,之前那张图对
不等号放缩,可以得到:
最优二叉树可能有很多种(交换左右子树),这里说明权值相等。
Huffman 编码
数据的最小冗余编码问题 使得编码序列的总长度最小;
译码的唯一性原则 任一字符的编码都不能是另一个字符的前缀。
前缀码 设
求赋权连通图总长最小的支撑树;
两种算法:Kruskal, Prim.
将各边权重从小到大排序 while(最小生成树的边数<=总节点数-1) 找到最小的边权重,他连接的两边节点作为起始点 按从小到大的边权重顺序将节点加入图C中
定理:
否则,
需要先指定一个起始位置 while(最小生成树的边数<=总节点数-1) 寻找该点边权重最小的节点加入图C中 将图C看做一个整体,寻找C的所有边中权重最小的边,将所连点加入图C中
定理:假设
如果两点集之间连边为
引入:
还可以在连边上做文章,比如可以限语言相通,一人领航一人驾驶等。
定义匹配:令
最大匹配时
给定了
设
定理:
孤立顶点,当
初级回路,此时
初级道路,
注意
Hall 定理给出了判别完全匹配的条件:
证明:
若存在
若不存在完全匹配,则设
定理 在二分图
利用最小割最大流定理的证明:原点向左边连流量为
最大独立集是最小点覆盖的补集,如果补集中有两点相连,说明这条边没有在最小点覆盖中覆盖到。
我们考虑一个这样的问题,假设图
最小割对应的
再考虑从
再考虑怎么证明等号可以取到,这里,我们考虑朴素的贪心:看到了一条路径,就取这条路径。
假设我们第一次取
但是我们如果第一次取
类似于二分图最大匹配,我们采用反悔的机制。再考虑二分图最大匹配的证明,证明里面使用了对称差,其本质是一种加法,因此可以考虑给正向边和反向边都赋予权值,然后我们求出来路径里面,正向边和反向边是可以抵消的。
一开始,我们给所有正向的边赋予权值 1,所有反向的边赋予权值 0,假设我们决定取这条边,则正向赋予 0,反向赋予 1,代表我们可以反悔,通过后来反向取这条边,来不取这条边。
举例,假设我们先取了
容易发现存在路径
这两条路径进行抵消,可以得到
再考虑一条新路径和原路径抵消之后为什么会多出来一条路径,这个其实和二分图增广路的思想差不多,画个图比较容易理解。
再考虑为什么算法结束的时候,一定能找到
由之前的推导,
因此,
利用重边,这种方法可以推广到边权为整数的情况,进而推广到非整数的情况。
可以用这种方法理解网络流中的对偶性,即最大流=最小割,还可以用线性规划的方法理解:
假设有
转化为对偶形式,假设第
这其实就对应了最小割,表示任意一条路径都不能通过。
容易发现这样的线性规划
可得它的对偶问题为:
对应了最小割。
xxxxxxxxxx
331int dfs(int c, int t, int f) {
2 if (c == t) {
3 return f;
4 }
5 used[c] = true;
6 for (int i = 0; i < G[c].size(); ++ i) {
7 Edge &e = G[c][i];
8 if (!used[e.to] && e.cap > 0) {
9 int d = dfs(e.to, t, min(f, e.cap));
10 if (d > 0) {
11 e.cap -= d;
12 G[e.to][e.rev].cap += d;
13 return d;
14 }
15 }
16 }
17 return 0;
18}
19
20int max_flow(int s, int t) {
21 int flow = 0;
22 int cnt = 0;
23 for (;;) {
24 memset(used, 0, sizeof(used));
25 int f = dfs(s, t, INF);
26 cnt += 1;
27 if (f == 0) {
28 cout << cnt << endl;
29 return flow;
30 }
31 flow += f;
32 }
33}
效率低的原因,是因为一次只找一条增广路。
核心思想在于每次找多条增广路。
xxxxxxxxxx
201 bool BFS() {
2 memset(vis, 0, sizeof(vis));
3 queue<int> Q;
4 Q.push(s);
5 d[s] = 0;
6 vis[s] = 1;
7 while (!Q.empty()) {
8 int x = Q.front();
9 Q.pop();
10 for (int i = 0; i < G[x].size(); i++) {
11 Edge& e = edges[G[x][i]];
12 if (!vis[e.to] && e.cap > e.flow) {
13 vis[e.to] = 1;
14 d[e.to] = d[x] + 1;
15 Q.push(e.to);
16 }
17 }
18 }
19 return vis[t];
20 }
BFS 算法求出有余量的,构建分层图-
xxxxxxxxxx
151 int DFS(int x, int a) {
2 if (x == t || a == 0) return a;
3 int flow = 0;
4 for (int& i = cur[x]; i < G[x].size(); i++) {
5 Edge& e = edges[G[x][i]];
6 if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
7 e.flow += f;
8 edges[G[x][i] ^ 1].flow -= f;
9 flow += f;
10 a -= f;
11 if (a == 0) break;
12 }
13 }
14 return flow;
15 }
遍历分层图上的后继节点,只要当前可用流量能够承受,就继续分叉,这样可以一次找多条增广路。
如果图
如图,如果源点是橙色的点,汇点是绿色的点,建立对偶图,在源-汇连线左手侧的边界边连到最短路的超级源点,右手侧的边界边连到最短路的超级汇点,最短路即对应最小割。
发现这样平面图的节点数和边数都是
每条边新增单位流量的费用
思路是每次寻找单位流量费用最小的增广路:
xxxxxxxxxx
501struct qxx {
2 int nex, t, v, c;
3};
4
5qxx e[M];
6int h[N], cnt = 1;
7
8void add_path(int f, int t, int v, int c) {
9 e[++cnt] = (qxx){h[f], t, v, c}, h[f] = cnt;
10}
11
12void add_flow(int f, int t, int v, int c) {
13 add_path(f, t, v, c);
14 add_path(t, f, 0, -c);
15}
16
17int dis[N], pre[N], incf[N];
18bool vis[N];
19
20bool spfa() {
21 memset(dis, 0x3f, sizeof(dis));
22 queue<int> q;
23 q.push(s), dis[s] = 0, incf[s] = INF, incf[t] = 0;
24 while (q.size()) {
25 int u = q.front();
26 q.pop();
27 vis[u] = 0;
28 for (int i = h[u]; i; i = e[i].nex) {
29 const int &v = e[i].t, &w = e[i].v, &c = e[i].c;
30 if (!w || dis[v] <= dis[u] + c) continue;
31 dis[v] = dis[u] + c, incf[v] = min(w, incf[u]), pre[v] = i;
32 // 记录 SPFA 路径
33 if (!vis[v]) q.push(v), vis[v] = 1;
34 }
35 }
36 return incf[t];
37}
38
39int maxflow, mincost;
40
41void update() {
42 maxflow += incf[t];
43 for (int u = t; u != s; u = e[pre[u] ^ 1].t) {
44 e[pre[u]].v -= incf[t], e[pre[u] ^ 1].v += incf[t];
45 mincost += incf[t] * e[pre[u]].c;
46 }
47}
48
49// 调用:while(spfa())update();
50
法一:
利用不等式:
因此,若
法二:
数学归纳法。
显然
假设
然后再考虑多余的一个点,至多连出
再证明构造上届能取到……
假设
若存在两个不相交的道路
显然矛盾。
带弦回路的引理:如果简单图
假设
证明:数学归纳法。当
tips: 和边数相关的问题,常常使用数学归纳法。
极端情况,当
对于每一条边都如此求和,每个顶点的度数被求和的次数恰好为每个顶点的度数,因此:
由柯西不等式:
因此,
数学归纳法。
考虑
todo
这个好做……
运用缩点的思想
数学归纳法?
同构图判定:
这里就能看出
其中一个必定是 4 的倍数。
顶点度数,
如果有向,则顶点度数序列变为:
这时,对
一棵树有
因此,
因此:
和
设
设
圈
圈