离散数学这门课有个很容易让人误会的名字。你看到“逻辑、集合、归纳、计数、图论”,可能会以为这是把五六种零散工具装进同一个课名里;真正学进去之后会发现,它们一直在做同一件事:把一个问题说准确,再说明结论为什么一定成立。
这和只求一个数值的体验不太一样。计算题常常已经替你规定好了对象、运算和目标,你沿着熟悉的步骤往下算就行。离散数学却会不停追问:研究对象到底是什么?两个对象之间的关系是什么?“对所有对象都成立”和“至少有一个对象成立”差在哪里?试了许多例子之后,凭什么敢说下一个例子也不会出错?
第一次学证明时,最难的通常不是某个符号,而是老师写完“显然”“于是”之后,中间那一步你根本不知道从哪里来的。本课程会把这种思考过程摊开讲:为什么先回到定义,为什么要取一个任意对象,为什么一个反例就够推翻全称命题,以及为什么归纳假设不是循环论证。我们既要让论证正确,也要让别人看得懂它为什么正确。
先看最直观的区别。整数 一个接一个,可以逐个编号;一个有限字符串由有限个字符排成;一张课程表由课程、教室和时段组成;一个网络由节点和连接组成。这些对象彼此可区分,适合逐项讨论,我们把它们看成离散对象。
实数区间、曲线上的位置、连续变化的温度则不一样。任取两个不同实数,它们之间还能找到别的实数。研究这类对象时,我们常问极限、变化率、面积或连续性,这更接近连续数学的视角。

这里有两个常见误会。第一,离散不等于有限。自然数有无限多个,所有有限二进制串也有无限多个,但每个对象仍能被清楚地区分和按规则生成。第二,现实对象本身不会永远贴着“离散”或“连续”的标签,关键看我们准备回答什么问题。
例如,一天的时间可以看成区间 ,用来研究某个过程在任意时刻的变化;排课时又会把一天切成第一节、第二节、午间和晚间等有限时段。城市道路画在地图上是连续曲线,研究路由时却可以只保留路口和道路的连接关系。前一种模型保留位置与距离,后一种模型保留“能否从这里走到那里”。
判断一个模型是不是离散模型,不要只看现实对象能不能画成点。更可靠的问题是:我们是否把对象分成了可区分的单位,是否只保留这些单位之间的有限或可数关系,以及题目是否在问选择、顺序、连接、可达或数量。
你可以在下面的分类器里试几种对象。它的重点不是抢答,而是比较同一个对象在不同研究目的下为什么会有不同判断。
面对一个现实问题,离散数学不会急着套公式。我们先把题目压缩成一个可以推理的模型。这个过程通常有三步。
先决定对象是什么。排课问题里的对象可以是课程,网络问题里的对象可以是路由器,密码问题里的对象可以是每一位字符的选择。对象选错了,后面的式子再漂亮也回答不了原问题。
再说明对象之间有什么关系。两门课程可能因为有学生同时选修而冲突;两台路由器可能因为有链路而相邻;一个树节点可能通过父子边连接到下一层。关系不是图上的装饰,它保存了原问题的约束。
最后把目标写成明确问题:是否存在一个合法安排?所有合法输入都会终止吗?两点之间有没有路径?一共有多少种选择?这一步会决定我们需要证明、构造、计数,还是寻找反例。

假设有甲、乙、丙、丁、戊五门课。只要有学生同时选了两门课,这两门课就不能在同一时段考试。若一直盯着课程名称,我们很难看出问题的骨架;换一种表示就清楚了:
这样一来,“最少需要几个考试时段”就变成了“最少用几种颜色能完成合法着色”。顶点并不是真的圆点,边也不是真的线,颜色更不是在研究美术。它们只是把课程、冲突和时段换成了更容易推理的语言。
抽象时不是保留的信息越多越好。学生姓名、课程教室在这个模型里可能不重要,冲突关系却不能丢。一个合适模型应当刚好保留决定答案的信息。如果删掉的信息会改变答案,模型就删过头了;如果保留了一堆不会影响答案的细节,后面的推理只会更乱。
好的抽象不要求图画得像现实。它要求现实中的合法方案与模型中的合法结构能够对应起来,并且模型里得到的结论可以翻译回原问题。
下面的工作台把排课、网络、密码和树放在一起。切换场景时,可以一直盯着“对象—关系—问题”这条主线,看表面不同的问题怎样变成相似的离散结构。
我们先把“证明”说得朴素一点:证明是一条从已经接受的起点出发,经过有根据的逻辑步骤,到达目标结论的推理链。起点可以是定义、题目条件、已经证明过的结论或课程明确采用的基本规则;中间每一步都要能说明依据;最后要真正回到原命题,而不是停在“差不多看出来了”。

为什么不能只靠实验和算例?如果只问 是奇数还是偶数,算一次就能回答。但若命题是“任意两个奇数之和都是偶数”,它涉及无穷多对整数。你无法把这些整数一对一对全部试完。计算前一万组都成功,只能说明暂时没遇到反例,不能说明第一万零一组也一定成功。
更重要的是,证明不只给“正确”盖章,它还解释结论为什么成立。知道奇数的定义之后,下面这个证明几乎是被定义推着走出来的。
动笔前先说思路。结论里出现“奇数”和“偶数”,最自然的入口不是列举 ,而是把这两个词翻译成它们的定义。奇数能写成 ,偶数能写成 。我们的目标因此变成:把两个奇数的和整理成 乘某个整数。
取任意两个奇数,记为 和 。写“任意”很关键:我们没有偷偷挑选两个好算的数,后面的论证要对任何奇数都适用。
由奇数的定义,存在整数 ,使得 且 。这里用两个变量,是因为两个奇数没有必要来自同一个整数。
这个证明的计算只有一行,真正的工作却有四件:看出该展开哪个定义,选取任意对象,用变量保留一般性,再把整理后的式子送回目标定义。证明题常见的“没思路”,往往不是不会算,而是不知道该从哪个定义出发。
“设两个奇数都是 ”不是稳妥写法,因为它暗中让两个奇数相等。应该写成 和 。证明中的变量不是随手起的名字,它记录了对象之间允许相同还是可以不同。
数学探索常常从算例开始,这没有问题。画图、列小规模情形、写程序试验,都能帮我们看见结构。需要分清的是,例子在推理链里扮演什么角色。
考虑前 个奇数的和:
代入 ,得到 。这些数恰好是 ,于是我们猜想:
这个观察非常有价值,因为它告诉我们可能要证明什么,还暗示了“把每次增加的奇数看成正方形外面的一层”这种图形思路。但此刻它仍是猜想。要把“前四个都成立”升级成“每个正整数 都成立”,还缺一条覆盖任意 的一般论证。
全称命题说“范围里的每个对象都有某个性质”。要证明它,我们必须给出能覆盖整个范围的理由;要推翻它,却只需找出一个落在范围内、但不具有该性质的对象。
例如,“每个奇数都是素数”在 上都成立,但 是奇数且 ,所以命题立刻被推翻。反例不必多,一个合格的反例已经足够。
更能说明问题的是表达式
从 一直算到 ,结果都是素数。这样的连续成功很容易让人产生信心。可是在 时,
它不是素数。前面四十个正确样本没有被浪费,它们帮助形成了一个很有吸引力的猜想;只是这个猜想最终遇到了反例。数学上成熟的做法不是埋怨反例“太特殊”,而是回头修改命题,或者寻找真正能解释现象的条件。

证明方法并不是看到题目后随便挑一种。命题的逻辑形状会给出方向。尤其要先看清它说的是“对所有对象”“存在一个对象”“如果条件成立,那么结论成立”,还是“两个条件恰好等价”。
若目标是“所有偶数的平方都是偶数”,我们会取一个任意偶数 ,然后只使用“ 是偶数”这个条件推理。因为没有利用 的特殊数值,所以论证能够覆盖每个偶数。
反过来,只证明 是偶数,覆盖的只是三个对象。这里最该问的不是“我还要再算几个”,而是“我能不能用定义一次处理任意偶数”。
若目标是“存在一个大于 的偶素数”,这句话是假的,因为唯一的偶素数是 。若目标改成“存在一个大于 的偶合数”,给出 并检查它满足条件,就已经完成存在性证明。
所以例子并非永远不能当证明。它不能证明全称命题,却常常正是存在命题所需要的见证。关键不在“例子多不多”,而在命题究竟要求覆盖多少对象。
面对“如果 ,那么 ”,最直接的思路是暂时假设 成立,再利用定义和已知事实推出 。如果走不通,还可以考虑证明逆否命题、分类讨论或反证。但无论使用哪种方法,我们都要清楚前件、后件和允许使用的条件。
这些差别很快会变成逻辑符号中的全称量词、存在量词、蕴含和等价。现在先不用背符号,先养成一个习惯:每次证明前,用普通中文把命题的范围和方向读准确。
课程后面会出现不少新名词,但学习路线并不是每到一章就重新开始。前面的语言会一直留在后面的证明里。

我们从命题开始,研究“且”“或”“非”“如果……那么……”和“当且仅当”。真值表会迫使我们检查所有真值组合,逻辑等价会帮助我们把难处理的命题换成更方便的形式。量词则让“每一个”“至少一个”“不存在”有准确含义。
这一步看起来像语法课,实际上是在清理证明的输入。如果一句话连真假条件都含糊,后面的推理不可能可靠。
集合回答“我们正在讨论哪些对象”;函数回答“每个输入对应哪个输出”;关系回答“哪些对象彼此有关”。图的边本身就是一种关系,计数问题经常是在数某个集合的元素,递推过程又常由函数或序列描述。
所以集合不是单独的一小章记号。后面说图的顶点集、边集,说函数是不是一一对应,说两种对象能否配对计数,都要回到集合语言。
直接证明适合从定义一路推出目标;分类讨论把全部情况分开处理;逆否和反证会改变推理入口;存在唯一性证明要分别处理“至少有一个”和“至多有一个”。方法名并不是固定模板,它们提醒我们当前要承担什么证明义务。
当命题按自然数编号,或者对象按递归规则逐层生成时,归纳法会出现。它先固定一个起点,再证明“只要当前一步成立,下一步也会成立”。归纳步骤证明的是一个条件关系,不是在无条件假设最终结论。
递归算法、递推数列、树的层次和字符串结构都带着“从较小对象生成较大对象”的味道。归纳正好沿着同一生成方向验证性质。
计数不只是把数字乘起来。我们会问:一次选择分几步?不同情形是否互斥?同一个结果被重复数了多少次?能否在两个集合之间建立一一对应?
密码空间的大小影响穷举难度,算法运行时间常来自操作次数,概率的分母和分子也依赖计数。一个可靠的计数解法必须解释为什么每个合法对象恰好被数到一次,或者为什么重复次数正好可以除掉。
在图论里,顶点表示对象,边表示成对关系。路径、连通、树、匹配、平面性和着色看起来是图形问题,本质上都在研究关系结构。考试排程是着色,网络路由是路径,任务依赖可用有向图表示,配对问题会进入匹配。
普通图可以有环,也可以让一个顶点连接多个邻居。树则是更受约束的图:它连通且无环。选定一个根之后,除根以外的每个顶点都能沿唯一方向追溯到父节点。正因为路径不会绕圈,树很适合表示文件目录、递归分解和层级关系。


逻辑正确是底线,但一串形式上没错的符号未必能帮助读者理解。刚开始写证明时,可以把它当成一篇很短的说明文:先告诉读者准备怎么走,再让每一步按顺序接上,最后亲手把结论扣回题目。
如果要分类讨论,就先说明按什么标准分、为什么这些情况没有遗漏;如果要反证,就说明准备假设目标结论不成立;如果要展开定义,就直接告诉读者“目标出现偶数,因此先把偶数写成 的形式”。
这几句话有时不属于形式推演,却能回答学生最关心的问题:“你是怎么想到第一步的?”
证明中的一句话应该接着上一句,并为下一句服务。不要在末尾突然调用一个从未说明的条件,也不要把关键理由藏在“显然”“容易看出”后面。真正简单的步骤可以简写,但首次出现的新动作最好交代依据。
只有一长串等号,读者很难知道每个等号为什么成立。公式适合承担计算,句子负责说明变量的含义、使用了什么定义,以及这一行怎样接近目标。证明不是把所有中文删掉之后剩下的式子。
当你已经得到 ,还应补上“ 是整数,所以 是偶数”。这不是多余重复,而是把计算结果和目标定义接起来。许多不完整证明的问题,正是作者在最后一步觉得“读者自己会懂”。
不要用“显然”“不难得到”替代自己还没补上的理由。如果你写下这些词后发现无法解释中间那一步,就把它展开;如果确实只是初等化简,也最好在第一次使用时说清楚变形依据。
写完后可以按下面的顺序做一次“证明对账”。
检查对象和范围:变量属于整数、实数、集合还是图中的顶点?是否在中途悄悄缩小了范围?
检查逻辑目标:你是在证明全称、存在、蕴含还是等价?若是“当且仅当”,两个方向是否都处理了?
检查每一步依据:它来自定义、题设、已知结论,还是前一步推导?有没有把要证明的结论偷偷当作前提?
检查结束位置:最后得到的事实是否正好就是题目要求,还是只得到一个看起来相近的式子?
这一章不要求你立刻写出复杂证明。它更像是在调整读题方式。以后看到一个新概念或一道题,先停几秒,依次问:
下一章会从最小的推理单位开始:什么样的语句能叫命题,几个命题怎样用“非、且、或、如果……那么……”连接,真值表又怎样穷尽检查所有真假组合。先把句子的逻辑结构看清楚,后面的集合证明、归纳、计数和图论论证才有可靠的起点。
把定义代入并整理:
因为整数对加法封闭,所以 仍是整数。
已经写成 乘一个整数。根据偶数的定义, 是偶数。由于 是任意选取的两个奇数,结论覆盖了所有情形。