学到这里,我们已经会写真值表、会处理集合和函数,也见过归纳、计数、树、着色与连通性。可一旦题目换成“怎么排考试”“怎么铺网络”“怎么证明程序不会出错”,很多人还是会愣一下:这些现实问题并没有在句尾提醒你“请使用图论”。
这正是综合建模真正难的地方。难点通常不在最后那几行计算,而在前面几步:哪些东西需要区分,哪些关系必须保留,目标究竟是存在性命题、全称命题,还是一个计数问题?如果这几步翻译错了,后面的证明越漂亮,离原问题反而越远。
这一章不再把知识点分开复述。我们会让三个案例从头走到尾:考试排程、园区网络和流式去重。每个案例都按同一条路线推进:

这一章反复区分两件事:证明负责说明“在这些定义和假设下,结论必然成立”;建模检查负责说明“这些定义和假设确实对应我们原来想解决的问题”。两件事缺一件,答案都不完整。
现实语言很喜欢使用“合理”“可靠”“尽量少”“不会出错”这些词。它们能表达愿望,却还不是数学命题。比如“这张课表很合理”到底是说没有学生撞考,还是说考试天数少,或者是说每个学生每天最多考一门?三种解释会得到三个不同模型。
第一次建模时,我建议先写一张五栏草稿。它不需要漂亮,但每一栏都必须能被检查。
这里有个很实用的判断:如果一句话还不能明确判真或判假,它通常还不是可证明的目标。“网络可靠”不是命题;“删除任意一条边后,任意两个站点之间仍存在路径”才是。
四种常见问法,对应四种完全不同的任务。
“我找到了一个三时段排法”只能证明三时段足够,不能证明三时段最少。要证明最少,还得说明两时段为什么不可能。建模时把这两个方向拆开,证明会清楚很多。
下面的工作台可以切换排课、网络和算法场景。你可以故意选择一个较弱的对象或证明方案,看看右侧的模型为什么失去说服力。
先看一个小型但完整的排程问题。现在有六门考试:逻辑、集合、归纳、计数、图论、算法。已知下列课程对有学生重叠,不能安排在同一时段:
我们想回答两个问题:两个时段够不够?如果有 个带标签的可用时段,一共有多少张合法课表?

把六门课程组成的集合记为 ,把 个时段组成的集合记为
一次完整排程必须给每门课程恰好一个时段,所以它是一个全函数
冲突是课程之间的对称关系:若逻辑与集合冲突,那么集合与逻辑也冲突;一门课程不会和自己形成这里所说的课程对。于是这个关系可以用简单无向图 表示。
这一步已经删掉了很多现实细节。课程名称只负责区分顶点,试卷页数和授课周数没有进入模型;学生重叠则必须保留,因为它正是“不能同场”的来源。
函数 是合法课表,当且仅当每条冲突边的两个端点被分到不同时段:
这恰好是正常顶点着色的定义。颜色不需要真的是红黄蓝;颜色只是时段标签。
于是“用 个时段排完考试”与“图 可以用至多 种颜色正常着色”不只是长得相似。它们是同一组函数满足同一组约束。
不要只说“排课问题可以看成图着色”。这句话少了最重要的一步:要明确课程怎样变成顶点、什么条件产生边、颜色怎样变成时段,并证明图着色的合法条件正好对应原问题的冲突条件。
这张冲突图连通且没有环,所以它是一棵树。我们准备证明两个结论。
第一,任意至少有两个顶点的树都可以用两种颜色正常着色,因此这个实例只要两个时段。
第二,对任意 和 ,一棵有 个顶点的树使用 个带标签颜色的正常着色数为
代入 、,三时段合法课表数是
这时先别急着庆祝。我们还欠两笔账:树为什么一定二着色,计数公式为什么没有重复也没有遗漏。
任选一个根顶点 。树是连通图,所以每个顶点 都能从 到达;树又没有环,所以 到 的简单路径唯一。令 表示这条路径的长度,并按长度奇偶给顶点分色:
若相邻顶点 得到了同一种颜色,那么 与 同奇偶。把从根到这两个顶点的唯一路径与边 放在一起,就会形成一个环;这和树无环矛盾。于是每条边两端颜色不同,构造确实给出了合法的两时段课表。
这个证明也告诉我们方案是怎么想到的:树没有环,沿根向外走时,每经过一条边就切换一次颜色,不会出现“绕一圈回来却要求自己换色”的麻烦。
接着证明着色数公式。这里最自然的归纳参数是顶点数,而不是颜色数。
归纳命题写成:对固定的 ,任意 个顶点的树都有 个正常 -着色。这里的“-着色”允许某些颜色没有使用,但 个颜色标签彼此不同。
注意最后那句“删掉 后只会回到一个小树着色”。它说明我们计数的对应关系是可逆的。如果只写“先给小树着色,再给叶子选颜色”,却不解释每张大课表是否恰好被数一次,乘法就还缺逻辑支撑。
这个模型有几条很清楚的边界。
这个案例把本课程的几块知识真正接上了:集合给出 和 ,关系给出 ,函数给出排程,逻辑量词定义合法性,图论识别树结构,归纳证明一般公式,计数法则给出方案总数。
第二个问题来自网络设计。五栋建筑需要用地下光缆连通:图书馆、实验楼、教学楼、食堂和宿舍。设计方提出三个层次的要求:平时任意两栋楼能通信;任意一条光缆损坏后仍能通信;如果所有光缆必须铺在同一层管沟里,线路之间不能交叉。
这三个要求看起来都在说“网络好不好”,数学上却是三种不同性质:连通性、删边后的连通性和平面性。

令 是建筑集合, 是实际铺设的光缆集合。若每对建筑之间最多有一条光缆,光缆没有方向,也不会从一栋楼连回自己,那么网络可以建模为简单无向图
一条从 到 的路径是顶点序列
其中每一对相邻顶点都由边连接。图连通,指的是每一对顶点之间都存在路径。
“删除任意一条边仍连通”可以直接写成
对至少有两个顶点的连通图,这也等价于图中没有割边。割边是删除后会让某些原本相连的顶点失去连接的边。
设网络有 个顶点和 条边。我们猜想:只要要求删除任意一条边后仍连通,就一定有
而且这个下界能达到:长度为 的环 恰好使用 条边,并能承受任意一条边故障。
这次要证明的是最优性,所以证明必须分成两半。下界说明任何方案都不能少于 条边;构造一个 条边的环说明 条边确实够用。
假设网络满足单边故障后仍连通。任意顶点 的度数不可能是 ,否则原图就不连通;度数也不可能是 ,因为删除 唯一关联的那条边会把 孤立。
因此每个顶点都满足
把所有顶点度数相加,每条无向边会在两个端点各贡献一次,所以握手引理给出
另一方面, 个顶点的度数都至少为 ,于是
两边除以 ,得到 。
这段证明没有猜线路应该怎么画。它从故障要求推出局部条件 ,再用握手引理把所有局部条件合成全局边数下界。很多网络下界证明都用这个套路:先问“每个点至少要承担什么”,再把局部总量对账。
把 个顶点首尾相接成环 ,边数正好是 。删除环上的任意一条边后,剩下的图是一条包含全部 个顶点的路径。路径中任意两点仍能沿线到达,所以删边后的图连通。
于是环既满足抗单边故障要求,又达到了所有可行方案的边数下界。若每条光缆成本相同,它在“光缆条数最少”这个目标下最优。
“环是一个可行方案”只证明了上界;“任何可行图至少有 条边”只证明了下界。上下界在 处相遇,我们才能说环在边数意义下最优。
如果线路交叉必须建设额外接点,而设计又禁止这种交叉,我们需要图是平面图。这里说“平面”,不是说当前草图恰好没有交叉,而是说这张图存在一种无边交叉的平面画法。
对一个连通简单平面图,设顶点数、边数和面数分别为 。欧拉公式的前提和结论是
当 时,每个面的边界长度至少为 ;每条边在所有面边界中一共被计算两次,因此
将 代入,得到简单连通平面图的边数上界
现在假设五栋楼之间都要求直接相连,模型就变成完全图 。它有
但平面边数上界只允许
因为 ,五栋楼两两直接连接的简单网络不可能无交叉地铺在同一平面。注意我们证明的是“不存在任何无交叉画法”,而不只是“我画的这张图有交叉”。
这个案例把路径、连通、割边、度数、握手引理和平面图放进了同一条推理链。定义负责把“可靠”拆细,下界证明负责说明最少成本,构造负责给出可执行方案,平面边数界负责识别额外物理约束是否可满足。
最后看一个算法问题。系统按顺序收到标识符序列
要求输出每个不同标识符第一次出现时的顺序。比如输入“甲、乙、甲、丙”,输出应该是“甲、乙、丙”。
代码看起来很简单:维护一个“见过的标识符集合” 和一个输出序列 。读到新标识符时,如果它不在 中,就加入 并追加到 ;若已经见过,就什么也不做。
真正要证明的不是“这段代码看起来合理”,而是:对每个有限输入序列,它都恰好输出所有不同标识符,既不重复,也不改变首次出现的先后次序。

处理完前 个输入后,把集合状态和输出序列分别记为 与 。初始状态是
从状态 读入 时,转移规则是
其中 表示把一个元素追加到序列末尾。
为什么同时维护集合与序列?集合适合回答“是否见过”,查询语义清楚;但集合不记录首次出现顺序。若只证明最终集合正确,还没有证明输出序列的顺序正确。
单写“ 存着已经见过的元素”还不够强,因为最终要求还包含输出不重复和顺序正确。我们把循环不变式写完整。处理完前 项后:
中的元素两两不同; 的元素集合恰好是 ;并且这些元素按照它们在输入中第一次出现的位置递增排列。
这四条合在一起,才足以在循环结束时推出完整后置条件。这里有一个很常见的经验:归纳步骤卡住时,问题未必是归纳法不合适,也可能是归纳命题写得太弱。把真正需要保留的信息一起写进不变式,后一步反而更容易证明。
证明按已经处理的元素个数 归纳。
初始化时 。空前缀中没有出现任何标识符,所以 正确;空序列没有重复,其元素集合也是空集,顺序条件自然成立。
这就是归纳在程序证明里的样子。基础情形对应初始化,归纳步骤对应一次状态转移保持性质,归纳结论说明所有可达轮次都满足不变式,终止时再把不变式翻译成输出结论。
假设标识符只能来自一个大小为 的有限集合 。长度为 的输入序列是从位置集合到 的函数,也可以看成 次有序选择。
每个位置都有 种选择,根据乘法法则,原始输入一共有
种。
当 时,不含重复的序列第一个位置有 种选择,第二个位置只能从剩下的 个标识符中选,依次类推,所以数量是
因此至少含一次重复的输入数为
当 时,不需要继续展开乘积。把 个输入位置当成对象,把 个标识符当成类别,映射 是一个从 元集合到 元集合的全函数。对象比类别多,鸽巢原理保证至少两个不同位置映到同一个标识符,所以每个长度为 的输入都含重复。
这里计数和证明各自回答不同问题:不变式保证去重算法对每个输入都正确;计数说明不同输入结构有多少种,并判断重复何时不可避免。
三个案例表面上差别很大,其实每一步都能对齐。
你可以把这张表当成以后做题时的检查顺序。先找对象,再写定义;猜想要有清楚量词;证明时检查所用定理的前提;最后故意拿最小规模和极端结构去撞模型。
综合题最容易出现一种“局部都对,整体却错”的证明:每行推导没毛病,但定理被用在不满足前提的对象上。下面几组前提值得反复核对。
一张图“看起来像树”、一次循环“跑了几个例子都对”、一张网络图“画出来有交叉”,都只是发现猜想的线索。证明需要从定义出发,覆盖量词要求的全部对象。
面对“找一个最好方案”,可以固定按三层证据组织答案。
先构造一个候选方案,并按定义验证它可行。排程要查每条冲突边,网络要查所有顶点可达,算法要查状态转移满足规格。
再给出任何方案都绕不过去的下界或必要条件。它可以来自奇环、度数总和、鸽巢原理,也可以来自一个反证。
最后比较候选方案与下界。如果两者相等,才得到最优性;若不相等,只能说我们有一个上界和一个下界,中间仍有空间。
下面的题目不只问最后的数值。先自己写出对象、定义、猜想、证明和边界,再展开答案核对。
某冲突图是一片森林,共有 个课程顶点和 个连通分量。现有 个带标签时段。证明合法排程数为
一个由七个站点组成的简单无向网络,要求删除任意一条边后仍连通。每条边成本相同。至少需要多少条边?请同时给出下界证明和达到下界的构造。
标识符集合有 个元素,输入序列长度为 。有多少个序列至少出现一次重复?
有人说:“一张有 个顶点、 条边的图满足 ,所以它一定是平面图。”这段话错在哪里?
这门课给出的不是一张“公式清单”,而是一套可以继续扩展的工作方式。后续方向不同,你要带走的主线也不同。
以后遇到一个新问题,可以先在纸上写五句话:对象是什么;合法对象怎样定义;我猜什么成立;证据覆盖了哪些量词;最小与极端输入会发生什么。只要这五句话能对上,离散数学里的证明、计数与图结构就不再是分散的工具,而会自然接到同一个模型里。
基础情形是 。单顶点树没有边,唯一顶点可以任选一种颜色,所以有 种着色,正好等于 。
假设所有 顶点树的公式成立。任取一棵 顶点树。顶点数至少为 的树有叶子,删去一个叶子 及其唯一关联边后,剩下的图仍是一棵 顶点树。
由归纳假设,较小的树有 种着色。对其中任意一种着色,叶子 只需要避开它唯一邻居的颜色,因此恰有 种扩展方法。每个大树着色删掉 后也只会回到一个小树着色,所以这一步无重无漏。
根据广义乘法法则,大树的着色数为
归纳步骤成立,公式得证。
假设处理完前 项后四条不变式都成立。现在读入 。如果 ,根据第一条不变式,它在前缀中已经出现过。算法不修改 和 ,因此元素集合、不重复性和首次出现顺序都保持不变。
如果 ,根据第一条不变式,它此前从未出现。把它加入 后,新集合正好等于前 项中出现过的标识符集合;把它追加到 不会造成重复。
新元素的第一次出现位置是 ,晚于 中所有元素的第一次出现位置,所以追加到末尾恰好保持首次出现顺序。于是无论成员测试结果是哪一种,不变式都从第 步保持到第 步。
循环在 时终止。此时输入前缀就是整个输入, 包含全部且仅有出现过的标识符; 无重复、元素集合等于 ,并按首次出现次序排列。因此算法满足要求。
边界上,空森林需要另行约定;这里默认每个连通分量至少有一个顶点,因此 。
所以 。把七个站点首尾连接成七边形环,恰好使用 条边;任意删一条边后得到包含所有顶点的路径,仍然连通。因此最少需要 条边。
这里数的是有序输入序列;若只数三元素多重集合,计数对象不同,答案也会改变。