一:约束满足问题 (CSP)
前面学的搜索算法(A*),是要找一条"通往终点的路"。
而 CSP 不是找路,它是"填坑"。坑位是固定的,选项是固定的,规矩也是死死的,我们的任务就是把坑填满,且不破坏任何规矩。
核心概念一:CSP 的三大基石与约束图
任何 CSP 问题都可以拆解为三个字母(必考基础):
- X (Variables) 变量: 需要填的坑。(如:地图上的湖南、湖北)。
- D (Domains) 值域: 每个坑里能填的选项。(如:{红, 绿, 蓝})。
- C (Constraints) 约束: 死规矩。
- 一元约束: 只限制一个变量(如:湖南不能涂红色)。
- 二元约束: 限制两个变量的关系(如:湖南和湖北颜色必须不一样)。
- 全局约束: 限制多个变量(如:数独里同一行 9 个数字必须全都不一样,)。
考场预测(作图/简答题):什么是约束图 (Constraint Graph)?
大白话: 把变量画成圆圈(节点),如果两个变量之间有"二元约束",就用线把它们连起来。
对策: 如果老师给你一个排课或者排座位的题目让你画约束图,只要找出哪两门课/哪两个人不能在一起,就在他们之间连条线。
核心概念二:约束传播 ------ "不用猜,靠推理"
- 节点相容:节点一致性 (Node Consistency): 满足所有的一元约束。比如规矩说"A不能是红色",你就直接去 A 的值域里把红色划掉。
- 弧相容:弧一致性 (极其重要,常考 AC-3 算法):
- 大白话原理: 假设 A 和 B 连着线(有约束)。如果你看了一眼 A 的值域(比如还有红色),你必须去 B 的值域里检查:"如果 A 真的涂了红色,B 还有没有别的颜色可涂?" 如果 B 没颜色涂了,说明 A 绝对不能是红色,立刻把红色从 A 的备选里划掉!
- 某变量值域中的所有取值满足该变量的所有二元约束 ------> 若某个值找不到任何可配合的邻居取值,就应当被删去
- 考试考法: 可能会给你几个变量和初始值域,问你"经过弧一致性检查后,A 的值域还剩什么?"去挨个试、挨个划。
- **通用弧相容:**Xi相对于某n元约束是相容的 ------> 删除死值,保留还有可能的值。
- **路径相容:**两个变量集合 {Xi,Xj} 对于第三个变量Xm是相容的,指{Xi,Xj}的每一个相容赋值{Xi=a,Xj=b}, Xm 都有合适的取值同时使得 {Xi,Xm} ,{Xm,Xj} 是相容的。 ------> 即使某两个变量之间看起来彼此兼容,它们的取值组合也可能在引入第三个变量后变得不可能。所以其思想在于不仅看两两关系,还看它们是否能通过第三个变量继续延伸。
核心概念三:回溯搜索与三大加速神器
将CSP描述为通用搜索问题,CSP 的求解过程,本质上是在"部分赋值空间"中搜索完整解。
目标:找到一个满足全部约束的完整赋值
状态:当前变量的部分赋值
初始状态:空赋值 {}
状态扩展:选择一个未赋值变量,为其赋一个与当前约束不冲突的值
目标测试:所有变量都已赋值,且满足全部约束
光靠推理不一定能填满所有坑,最后还是得靠"试错"(也就是带深度优先的回溯搜索)。但纯试错太慢,必须加上几个"启发式"加速器:
- 选哪个坑先填?(变量排序)
- 最少剩余值 : 挑最难填的坑(备选颜色最少的节点)先填。这叫"先捡硬骨头啃"。
- **度启发式 :**先处理高影响力变量,有助于更快传播限制。 挑牵连最广的坑(在约束图上连线最多的节点)先填。这叫"擒贼先擒王"。
- 给坑填哪个值?
- 最不约束值 (LCV ): 挑一个对别人影响最小的颜色。这叫"给别人留条活路"。
- 注意:变量排序是挑最苛刻的,值排序是挑最宽容的!
- 填完之后怎么扫尾?(交错搜索与推理)
- 前向检查 : 我刚给 A 涂了红色,立刻去所有和 A 连线的人那里,把他们的"红色"划掉。如果发现有人备选被划空了,立刻撤回 A 的红色。当某个变量被赋值后: 立刻检查它的未赋值邻居,删除与当前赋值不相容的值 ,若某个未赋值变量值域为空,则当前分支立即失败
核心概念四:局部搜索解 CSP (最小冲突启发式)
除了回溯,CSP 也能用上一节课学的"局部搜索"来解。
- 做法: 一开始闭着眼睛给所有坑瞎填一通(肯定会违反很多规矩)。
- 最小冲突法 (Min-conflicts): 每次随机挑一个违规的变量,把它改成一个能让全局冲突数量降到最低的值。就这么不断修修补补,通常很快就能解开百万级别的N皇后问题。
五:结合 25 年考题(第五大题 20 分深化复盘)
【考题重现】


第 (1) 问:CSP 建模与初始域计算 (10分)
【解题核心逻辑】
CSP 建模的第一步就是找"坑位(变量)"和"选项(值域)"。
- 变量 (Variables): 题目说"为了从学位课程毕业,必须完成以下四个要求"。这四个要求就是我们需要填的 4 个"坑位"。
- 初始域 (Initial Domains): 题目问的是初始域 !这就意味着,你不需要去管下面那一长串的"信息攻击性限制"、"基本算术限制"以及"不能重复计入"的条件。初始域只看最原始的选项清单。
【卷面标准答案(请直接这样写在答题纸上)】
解:(1) 对该问题进行 CSP 建模:
1. 变量集合 X:
我们将 4 个毕业要求定义为变量集合:
X = {算法要求, 机器学习要求, 通信要求, 信息战要求}
2. 每个变量的初始域 D:
根据题目给出的各个要求对应的可选课程,各变量的初始域如下:
- D(算法要求)= { (CS-5211, CS-5212), (CS-5211, CS-5381), (CS-5681, CS-2484) }
- D(机器学习要求)= { CS-5381, CS-5681, CS-8310 }
- D(通信要求)= { CS-2484, CS-7311, CS-7122 }
- D(信息战要求) = { CS-5381, CS-9601 }
第 (2) 问:提高 CSP 回溯算法效率的三种方法及其定义 (10分)
解:
方法一:最少剩余值启发式 (MRV - Minimum Remaining Values)
- 定义: 在选择下一个要赋值的变量时,优先选择当前合法取值(剩余选项)最少的那个变量进行赋值。
- (大白话记忆:先捡硬骨头啃,优先填最容易引发冲突的、选择最少的坑。)
方法二:度启发式 (Degree Heuristic)
- 定义: 在选择下一个要赋值的变量时,优先选择参与了最多未赋值变量约束的变量进行赋值。(通常作为 MRV 策略出现平局时的打破规则)。
- (大白话记忆:优先处理"牵连最广、限制别人最多"的那个节点。)
方法三:前向检查 (Forward Checking)
- 定义: 每当为一个变量赋予一个值后,立刻检查所有与该变量有约束关系的未赋值变量。从这些未赋值变量的域中,删除与当前赋值相冲突的取值。如果发现某个变量的域变为空,则立刻触发回溯。
- (大白话记忆:走一步看几步。我选了一个值,立刻把别人不能用的选项划掉,提前发现死路。)
方法四:最不约束值启发式 (LCV - Least Constraining Value)
- 定义: 在为一个已经选定的变量选择具体的取值时,优先选择那个排除掉其他未赋值变量可用选项最少的值。
- (大白话记忆:给别人留条活路。尽量选那些不怎么影响其他变量的选项。)
二:逻辑 Agent 与命题逻辑
核心概念一:基于知识的 Agent
如果把之前的 Agent 比作只会走迷宫的"小车",那 KBA 就是一个"带了笔记本的侦探"。
- 知识库: 它的笔记本。里面写满了一条一条的"事实"和"规则"(也就是句子)。
- 两大核心动作(必考常识):
- TELL(告诉): 把新发现的线索写进笔记本。
- ASK(询问): 问笔记本"根据现在的线索,结论 X 成立吗?"
核心概念二:逻辑学的基本黑话 (语法、语义、蕴涵)
这里有几个学术词汇,选择题/判断题极爱考概念混淆:
- 语法 (Syntax): 句子写得对不对。比如
A + B =是错的,A + B = C是对的。 - 语义 (Semantics): 句子表达的意思在现实中是真 (True) 还是假 (False)。
- 蕴涵 (Entailment):
- 大白话: 如果 A 是真的,那 B 必然是真的。这就叫 A 蕴涵 B
- 举例: A ="张三在湖南大学",B ="张三在长沙"。因为 A 真则 B 必真。
核心概念三:经典测试环境 ------ Wumpus 世界 (怪兽世界)
这是一个 4x4 的网格地牢,里面有金子、有陷阱 (Pit)、有吃人的怪兽 (Wumpus)。
- 规则:
- 陷阱旁边一格会有"微风 (Breeze)"。
- 怪兽旁边一格会有"恶臭 (Stench)"。
- 逻辑推理体验: Agent 走到 (1,1),没风没臭。走到 (1,2) 感觉到了微风。Agent 不用走进去,就能在脑子里推理出:"(1,3) 或者 (2,2) 肯定有陷阱!"这就是逻辑 Agent 的威力。
核心概念四:命题逻辑与"合取范式 (CNF)"
这是你试卷上明确考到的知识点!计算机不认识我们平时写的长篇大论的逻辑公式,它只认识一种极其死板、极其标准化的格式,叫作合取范式。
- 大白话定义: CNF 就是一堆括号用 "与" 连接起来,而每个括号里面只能是字母和 "或"。
【CNF 转换口诀】:
- 消灭双箭头
- 消灭单箭头
- 把非号 塞进括号里(德摩根定律):
- 分配律
五:结合 25 年考题(第四大题第(1))

解:
第一步:消去双向蕴涵(⇔)
原式 B₁₁ ⇔ (P₁₂ ∨ P₂₁),等价于两个蕴涵的合取:
(B₁₁ ⇒ (P₁₂ ∨ P₂₁)) ∧ ((P₁₂ ∨ P₂₁) ⇒ B₁₁)
第二步:消去蕴涵(⇒)(利用X⇒Y ≡ ¬X ∨ Y)
前半部分:¬B₁₁ ∨ P₁₂ ∨ P₂₁
后半部分:¬(P₁₂ ∨ P₂₁) ∨ B₁₁
合并后:(¬B₁₁ ∨ P₁₂ ∨ P₂₁) ∧ (¬(P₁₂ ∨ P₂₁) ∨ B₁₁)
第三步:否定符号(¬)移到内部(德摩根定律)
后半部分¬(P₁₂ ∨ P₂₁) 转化为:¬P₁₂ ∧ ¬P₂₁
此时式子变为:(¬B₁₁ ∨ P₁₂ ∨ P₂₁) ∧ ((¬P₁₂ ∧ ¬P₂₁) ∨ B₁₁)
第四步:使用分配律(∨分配到∧)
对后半部分((¬P₁₂ ∧ ¬P₂₁) ∨ B₁₁)分配,得到:(¬P₁₂ ∨ B₁₁) ∧ (¬P₂₁ ∨ B₁₁)
第五步:最终合取范式(CNF)
(¬B₁₁ ∨ P₁₂ ∨ P₂₁) ∧ (¬P₁₂ ∨ B₁₁) ∧ (¬P₂₁ ∨ B₁₁)
核心概念五:归结原理 (Resolution) ------ 机器怎么证明?
我们人类证明问题喜欢顺着推,但计算机不擅长。计算机最擅长的是"反证法"。
- 大白话原理: 知识库里有很多线索。你想证明结论 A 是对的。那你就先把 "A是错的 " 扔进知识库。然后让计算机用 CNF 去互相碰撞(归结)。如果最后撞出了一个"矛盾(空子句)",那就说明"A 是错的"这个假设不成立,反过来证明了 A 是对的!
三:一阶逻辑与归结证明
如果命题逻辑是"判断题(只管对错)",那一阶逻辑就是"填空题和连线题"。它认为这个世界是由"对象(具体的人或物)"和它们之间的"关系"组成的。
核心概念一:一阶逻辑的"三大零部件"
要把人类的自然语言翻译成机器能看懂的一阶逻辑,你手里只有这三种积木:
- 常量 (Constants): 具体的名字。比如:
老李,大李,湖南大学。 - 变量 (Variables): 代表未知的代词。比如:
x,y,z。 - 谓词 (Predicates): 表示属性或关系(通常是个动词,结果为真或假)。比如:
Father(x, y)表示"x 是 y 的父亲";Student(张三)表示"张三是学生"。
核心概念二:量词------ 必考符号
当你用变量 x 的时候,你必须告诉计算机这个 x 代表多少人:
- 全称量词: 表示"所有的、任意的"
- 存在量词 : 表示"至少存在一个、有的人"
核心概念三:一阶逻辑的归结证明流程
这套流程就是你试卷大题的标准解题模板,计算机都是靠"反证法"来办案的:
- Step 1(翻译): 把题目里的已知条件,全部翻译成一阶逻辑公式。
- Step 2(立反贼): 把题目让你证明的结论取反,扔进已知条件里。
- Step 3(化标准): 把所有句子全部变成合取范式 (CNF)。
- Step 4(合一与归结): 像消消乐一样,把一正一反的谓词抵消掉。因为一阶逻辑带有变量
x和y,在抵消前,必须给它们赋予具体的人名,这在学术上叫合一 (比如把x替换成老李)。如果最后消出了一个"矛盾"(空子句),证明就成功了!
五:结合 25 年考题(第四大题第 2、3 问)

解:(2)
定义谓词 Father(x, y) 表示 x 是 y 的父亲,Grandfather(x, y) 表示 x 是 y 的祖父。
根据题意,上述关系的谓词逻辑表示如下:
如果x是y的父亲,y又是z的父亲,则x是z的祖父:
对于所有 x, y, z (Father(x, y) 且 Father(y, z) 推出 Grandfather(x, z))
老李是大李的父亲:
Father(老李, 大李)
大李是小李的父亲:
Father(大李, 小李)
解:(3)
第一步:将要证明的结论取反。
题目要证明"存在祖孙关系",即证明 存在 u, v Grandfather(u, v)。
将其取反得到目标子句:非存在 u, v Grandfather(u, v),化简量词即为:
对于所有 u, v 非 Grandfather(u, v)
第二步:将所有前提和取反后的结论转化为子句集 (CNF 格式)。
将前提 1 中的蕴涵符号消除(利用 A 推出 B ≡ 非A 或 B 规则,以及德摩根定律 非(A 且 B) ≡ 非A 或 非B):
Father(x, y) 且 Father(y, z) 推出 Grandfather(x, z)
化为:非(Father(x, y) 且 Father(y, z)) 或 Grandfather(x, z)
最终子句 (1): 非 Father(x, y) 或 非 Father(y, z) 或 Grandfather(x, z)
前提 2 是事实,直接作为子句 (2): Father(老李, 大李)
前提 3 是事实,直接作为子句 (3): Father(大李, 小李)
取反后的结论作为子句 (4): 非 Grandfather(u, v)
第三步:进行归结推导(找矛盾)。
归结 1: 将子句 (2) Father(老李, 大李) 与子句 (1) 进行归结。
作变量代换(合一):{x / 老李, y / 大李}
消去相反项,得到新子句 (5): 非 Father(大李, z) 或 Grandfather(老李, z)
归结 2: 将子句 (3) Father(大李, 小李) 与新子句 (5) 进行归结。
作变量代换(合一):{z / 小李}
消去相反项,得到新子句 (6): Grandfather(老李, 小李)
归结 3: 将新子句 (6) 与 取反结论子句 (4) 非 Grandfather(u, v) 进行归结。
作变量代换(合一):{u / 老李, v / 小李}
正反完全抵消,得到空子句 (NIL 或 空子句)。
结论:
因为推导出了空子句,说明产生矛盾,反证法成功。原结论成立,即存在祖孙关系。
根据归结过程中的变量代换 {u / 老李, v / 小李},得出老李和小李是祖孙关系。