Chap1 算法导论与稳定匹配
返回:0400 算法设计与分析总目录 · 下一章:0402 Chap2 算法分析基础
1、学习目标
算法设计的第一步不是写代码,而是把现实问题压缩成清楚的数学对象:输入是什么,输出是什么,什么叫合法,什么叫更好。本章用稳定匹配作为第一个完整案例,练习从问题建模到算法证明。
| 模块 | 要掌握的内容 |
|---|---|
| 问题形式化 | 输入、输出、约束、目标 |
| 稳定匹配 | 偏好列表、匹配、阻塞对、稳定性 |
| Gale-Shapley | 求婚方提出、接受方保留、迭代收敛 |
| 正确性证明 | 终止性、完备性、稳定性 |
| 复杂度 | 每对最多被提议一次,所以 O(n^2) |
2、算法问题如何描述
一个算法问题通常写成:
1 | 输入:满足某些条件的数据对象 |
比如排序:
1 | 输入:n 个可比较元素 |
稳定匹配:
1 | 输入:两组人数相等的对象,每个人给出对另一组的偏好排序 |
3、稳定匹配问题
设有 n 个学生和 n 个学校,双方都给出对另一方的完整偏好列表。
基本概念:
| 概念 | 说明 |
|---|---|
| 匹配 | 每个学生分配给一个学校,每个学校接收一个学生 |
| 完美匹配 | 所有人都被匹配 |
| 阻塞对 | 学生和学校彼此都更喜欢对方,而不是当前匹配对象 |
| 稳定匹配 | 不存在任何阻塞对 |
阻塞对是稳定匹配的核心。它表示当前结果里有一对双方都有动力私下换掉现有搭档,因此这个结果“不稳定”。
4、Gale-Shapley 算法
以学生向学校提出申请为例:
1 | while 存在未匹配且还没申请完的学生: |
这个算法有两个很重要的动态:
- 学生的选择只会越来越差,因为他按偏好从高到低申请。
- 学校手里的暂定对象只会越来越好,因为它每次保留更喜欢的人。
5、终止性
每个学生最多向每个学校申请一次,总申请次数最多 n^2。每次循环至少发生一次新的申请,所以算法一定会终止。
1 | 申请次数 <= n * n |
这类证明很常见:找到一个单调变化且有上界的量。这里的量就是“已经发出的申请数量”。
6、完备性
算法结束后,不会有人没被匹配。
证明思路:
- 假设某个学生
s未匹配。 - 若他还没申请完,算法不应停止。
- 若他申请过所有学校,则每个学校都至少收到过申请。
- 学校收到申请后会一直保留一个暂定对象,不会变空。
- 那么所有学校都有人,学生总数和学校总数相等,
s不可能未匹配。
所以算法结束时得到完美匹配。
7、稳定性
假设算法结果存在阻塞对 (s, c),即:
s更喜欢c,而不是当前学校。c更喜欢s,而不是当前学生。
因为 s 按偏好从高到低申请,既然他更喜欢 c,他一定在当前学校之前向 c 申请过。
当时有两种情况:
c接受了s,但后来只可能换成更喜欢的人。c拒绝了s,说明当时已有更喜欢的人,后面也只会更好。
因此最终 c 不可能更喜欢 s 胜过当前学生,矛盾。算法结果稳定。
8、复杂度
| 部分 | 复杂度 |
|---|---|
| 申请次数 | O(n^2) |
| 若偏好比较用顺序扫描 | 可能到 O(n^3) |
| 若预处理排名表 | O(n^2) |
| 总复杂度 | O(n^2) |
实现时通常预处理:
1 | rank[c][s] = 学校 c 对学生 s 的排名 |
这样比较两个学生谁更受学校喜欢就是 O(1)。
9、算法设计启发
稳定匹配这个例子给出的训练价值:
| 训练点 | 启发 |
|---|---|
| 建模 | 先定义阻塞对,才能定义稳定性 |
| 算法 | 简单规则反复执行,也可能得到全局性质 |
| 证明 | 终止性、完备性、稳定性要分开证明 |
| 数据结构 | 预处理排名表能把比较降到 O(1) |
| 结果偏向 | 哪一方提出申请,结果会偏向哪一方 |
10、易错点
| 易错点 | 修正 |
|---|---|
| 把稳定理解成双方都最满意 | 稳定只要求不存在阻塞对 |
| 忘记证明完美匹配 | 稳定性之前先证明所有人都匹配 |
| 学校拒绝后还可能后悔 | 学校手里的人只会越来越好 |
| 复杂度只看循环 | 偏好比较如果不预处理会多一层 |
| 认为稳定匹配唯一 | 稳定匹配可能不唯一 |
11、复盘清单
| 检查项 | 状态 |
|---|---|
| 能形式化描述一个算法问题 | 待复盘 |
| 能解释阻塞对和稳定匹配 | 待复盘 |
| 能手动模拟 Gale-Shapley 算法 | 待复盘 |
| 能证明算法终止 | 待复盘 |
| 能证明结果稳定 | 待复盘 |
| 能说明为什么预处理排名表 | 待复盘 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ruiqy~!







