📝 我的笔记

还没有笔记

选中页面文字后点击「高亮」按钮添加

7_时间复杂性7.5.ZH解释

📜 原文
📖 逐步解释
∑ 公式拆解
💡 数值示例
⚠️ 易错点
📝 总结
🎯 存在目的
🧠 直觉心智模型
💭 直观想象

11. 额外的NP-完全问题

1.1. NP-完全现象的普遍性

📜 [原文1]

NP-完全现象普遍存在。NP-完全问题出现在许多领域。由于人们不完全了解的原因,大多数自然出现的 NP 问题要么已知属于 P 类,要么属于 NP-完全类。如果你正在为新的 NP 问题寻找多项式时间算法,那么投入部分精力尝试证明它属于 NP-完全是明智的,因为这样做可以防止你为寻找一个不存在的多项式时间算法而徒劳。

📖 [逐步解释]

这段话是对 NP-完全 (NP-Complete) 这个概念在现实世界中的普遍性和重要性的一个宏观介绍。

  1. “NP-完全现象普遍存在。NP-完全问题出现在许多领域。”
    • 这句话指出,NP-完全问题不是计算理论中一个罕见的、孤立的特例,而是一种广泛存在的现象。
    • 在计算机科学的许多分支,如运筹学(例如旅行商问题)、人工智能(例如规划问题)、网络设计(例如顶点覆盖)、密码学、生物信息学等领域,都会遇到大量的 NP-完全问题。它们是“自然出现”的,而不是被人为构造出来的难题。
  2. “由于人们不完全了解的原因,大多数自然出现的 NP 问题要么已知属于 P 类,要么属于 NP-完全类。”
    • 这里提到了一个有趣的观察,被称为“NP 问题的二分法”或“拉德纳定理 (Ladner's Theorem)”的某种体现。
    • P 类问题 (Polynomial time) 是指那些存在多项式时间算法,能够在合理时间内解决的问题。例如,排序、查找最短路径。
    • NP 类问题 (Nondeterministic Polynomial time) 是指那些解的正确性可以在多项式时间内验证的问题。
    • NP-完全问题NP 问题中最难的一类。
    • 这句话的意思是,当我们发现一个新的 NP 问题时,它很大概率最终会被证明要么是“简单的”(属于 P 类),要么是“最难的”(属于 -完全)。介于两者之间的“NP-中间问题”(即,既不是 P 也不是 NP-完全)虽然理论上存在(由拉德纳定理证明),但在实践中非常罕见。整数分解问题和图同构问题曾被认为是 NP-中间问题的候选者,但它们的确切地位仍是未解之谜。
    • 这个现象的原因尚不完全清楚,但它指导着我们研究问题的策略。
  3. “如果你正在为新的 NP 问题寻找多项式时间算法,那么投入部分精力尝试证明它属于 NP-完全是明智的...”
    • 这提供了一个非常实用的研究建议。当你面对一个你不知道解法复杂度的 NP 问题时,你有两条路可以走:
  4. 尝试设计一个多项式时间算法来解决它。如果成功,你就证明了这个问题属于 P 类,这是一个重大的理论突破(如果该问题之前被认为是难的)。
  5. 尝试证明这个问题是 NP-完全的。
    • 这个建议的核心在于,这两条路是互斥的(假设 P ≠ NP)。如果一个问题是 NP-完全的,那么它就不可能存在多项式时间算法
  6. “...因为这样做可以防止你为寻找一个不存在的多项式时间算法而徒劳。”
    • 这是上述建议的直接结果。如果你成功地证明了一个问题是 NP-完全的,你就得到了一个“坏消息”,但这个坏消息非常有价值。它告诉你,不要再浪费时间和资源去尝试寻找一个高效的、精确的、能在所有情况下都快速解决问题的算法了,因为这样的算法(在 P ≠ NP 的前提下)根本不存在。
    • 知道一个问题是 NP-完全的,可以让你改变策略,转而寻求近似算法、启发式算法、或者只针对特定情况的特例算法,而不是一头扎进一个死胡同。
💡 [数值示例]
  • 示例1:旅行商问题 (TSP)
  • 问题描述:给定一系列城市和每对城市之间的距离,求一条访问每个城市恰好一次并返回起点的最短路径。
  • 分类:这是一个经典的 NP-完全问题。
  • 研究策略:一个刚接触此问题的研究者可能会尝试各种算法(如贪心法、动态规划)来寻找一个在任何城市规模下都很快的最优解法。然而,当他了解到 TSPNP-完全的之后,他就会明白,对于大规模问题(例如几百个城市),寻找精确的最短路径是极其耗时的。他可能会转向设计近似算法,比如找到一条长度不超过最优路径长度 1.5 倍的路径,这样的算法是存在的且运行速度快得多。
  • 示例2:2-SAT 问题 (2-Satisfiability)
  • 问题描述:给定一个由若干子句组成的布尔公式,其中每个子句都是两个文字(变量或其否定)的析取(或运算),判断是否存在一组变量赋值使得整个公式为真。例如:$(x_1 \lor \overline{x_2}) \land (\overline{x_1} \lor x_3) \land (x_2 \lor \overline{x_3})$
  • 分类:这是一个 P 类问题。存在线性的时间复杂度的算法可以解决它。
  • 研究策略:对于 2-SAT,研究者可以放心大胆地去设计高效算法,因为他们知道这样的算法是存在的。他们不必担心这个问题是“不可解”的(在多项式时间内)。这与 3-SAT(每个子句有三个文字)形成鲜明对比,3-SATNP-完全的。
⚠️ [易错点]
  1. 误解1:NP 问题都是难解的。
  2. 辨析:这是最常见的误解。NP 只是一个分类,它包含了所有 P 类问题。P 类问题是“容易”的。所以,说一个问题是 NP 问题,只说明它的解容易验证,并没有说明它本身是否难解。只有 NP-完全NP-难问题才被认为是“难解”的。
  3. 误解2:如果我证明了一个问题是 NP-完全的,就意味着它永远无法解决。
  4. 辨析:并非如此。NP-完全的证明只是说,在 P ≠ NP 的假设下,不存在一个在最坏情况下运行时间是多项式级别精确算法。对于实际应用中的许多 NP-完全问题实例,我们仍然可以:
  5. 用指数级算法解决小规模的实例。
  6. 找到近似解(例如,找到一个接近最优的解)。
  7. 使用启发式方法,在大多数“典型”实例上表现良好,尽管在某些最坏情况下可能很慢或找不到解。
  8. 解决问题的某个有特殊结构的子集。
  9. 边界情况:P vs NP 问题。
  10. 整个讨论都建立在 P ≠ NP 这个悬而未决的猜想之上。如果有一天有人证明了 P = NP,那么所有 NP-完全问题都将拥有多项式时间算法,这里的“明智建议”就会失效。但目前,学术界和工业界普遍基于 P ≠ NP 的假设进行工作。
📝 [总结]

本段是关于 NP-完全问题研究策略的指导性引言。它强调了 NP-完全问题的普遍性,并指出了一个重要的研究现象:大多数 NP 问题要么简单 (属于 P),要么极难 (属于 NP-完全)。基于此,它提出了一个实用的建议:在为一个新的 NP 问题寻找高效算法时,应同时尝试证明其为 NP-完全。成功证明其 NP-完全性虽然意味着找不到通用的高效解法,但能避免在错误的方向上浪费精力,从而引导研究转向更现实的解决方案,如近似算法。

🎯 [存在目的]

本段的目的是为后续介绍具体的 NP-完全问题证明做铺垫。它首先建立起一个“为什么要证明一个问题是 NP-完全”的宏观认知。它告诉读者,进行这种证明不仅仅是一个理论练习,更是一种在算法研究和应用开发中至关重要的策略性步骤,可以帮助我们识别问题的内在难度,从而做出明智的决策。

🧠 [直觉心智模型]

你可以把所有 NP 问题想象成一个巨大的“问题大陆”。

  1. 大陆上有一片富饶的、容易开发的平原,叫做“P 域”,这里的问​​题都有现成的、快速的解决方法(多项式时间算法)。
  2. 大陆上还有一片极其险峻、无法逾越的山脉,叫做“NP-完全山脉”,这里的问​​题本质上都一样难,只要你能征服其中一座山峰,你就等于能征服所有山峰。
  3. 当你遇到一个新问题,它就像是降落在这片大陆的一个未知地点。你的任务是确定你的位置。
  4. 本段的建议是:你不要只朝着平原(P 域)的方向埋头猛冲。你应该同时观察一下周围的地形,看看有没有迹象表明你其实身处“NP-完全山脉”的脚下。如果你能证明自己就在山脉脚下,你就知道攀登是徒劳的(在现有技术下),应该考虑绕路(近似算法)或者造一架飞机(量子计算等未来技术)。
💭 [直观想象]

想象你是一个寻宝猎人,宝藏是一个能解决某个问题的“高效算法”。你面前有一张藏宝图,上面标记了“NP 问题”这个区域。

  1. 你知道这个区域里有些地方埋着“P 类”宝藏,很容易挖到。
  2. 但也有些地方被下了“NP-完全”魔咒,任何试图直接挖掘宝藏的人都会陷入无尽的循环,永远也挖不到。
  3. 本段文字就像一位老猎人给你的忠告:“孩子,在你开始疯狂挖掘之前,先花点时间研究一下你脚下的土地。学会识别‘NP-完全’魔咒的迹象。如果你发现这里被施了魔咒,就别挖了,赶紧换个地方,或者改变目标,挖点旁边的‘近似解’小宝石也好。否则,你只会在这里白白浪费一生。”

1.2. 归约策略概述

📜 [原文2]

在本节中,我们介绍额外的定理,表明各种语言是 NP-完全的。这些定理提供了这类证明中使用的技术的例子。我们的通用策略是展示从 3SAT 到相关语言的多项式时间归约,尽管为了方便,我们有时会从其他 NP-完全语言进行归约。

📖 [逐步解释]

这段话简要说明了本节内容的核心——如何证明一个问题是 NP-完全的,并点明了所采用的主要技术手段。

  1. “在本节中,我们介绍额外的定理,表明各种语言是 NP-完全的。”
    • 这明确了本节的目标:不是介绍一个,而是介绍一系列的 NP-完全问题。这里的“语言”是形式语言理论中的术语,可以理解为“问题”的严格数学定义。例如,CLIQUE 语言是所有编码了“包含特定大小团的图”的字符串集合。证明一个语言是 NP-完全的,等价于证明对应的问题是 NP-完全的。
  2. “这些定理提供了这类证明中使用的技术的例子。”
    • 本节的目的不仅仅是罗列 NP-完全问题,更重要的是教学。通过展示几个具体的证明过程,让读者学习和掌握证明 NP-完全性的一般方法和技巧。这些技巧,特别是“归约”的构造,是计算复杂性理论的核心技能之一。
  3. “我们的通用策略是展示从 3SAT 到相关语言的多项式时间归约...”
    • 这里揭示了核心战术:多项式时间归约 (Polynomial-time reduction)
    • 要证明一个新问题 B 是 NP-完全的,标准的两步流程是:
  4. 证明 B 属于 NP。(这通常比较简单,只需说明给定一个解,可以在多项式时间内验证其正确性)。
  5. 证明一个已知的 NP-完全问题 A 可以多项式时间归约到 B(记作 $A \le_P B$)。
    • “从 3SAT” 指的是,我们将选择 3SAT 问题作为那个“已知的 NP-完全问题 A”。3SAT 是第一个被证明为 NP-完全的问题(根据库克-莱文定理),并且它的结构(与、或、非逻辑)非常基础,适合用来模拟和构造其他问题。它就像是 NP-完全世界里的“万恶之源”或“干细胞”,可以“分化”成各种各样其他的问题。
  6. “...尽管为了方便,我们有时会从其他 NP-完全语言进行归约。”
    • 这补充说明了归约的灵活性。虽然从 3SAT 出发是最根本的方法,但有时并不方便。
    • NP-完全性具有传递性:如果 $A \le_P B$$B \le_P C$,那么 $A \le_P C$
    • 这意味着一旦我们证明了某个新问题 B 是 NP-完全的,我们就可以把它加入我们的“已知 NP-完全问题工具箱”。在将来要证明另一个问题 C 是 NP-完全时,如果发现从 B 归约到 C 比从 3SAT 归约到 C 更简单、更直观,我们完全可以这么做。这形成了一个“归约链”。例如,在证明 哈密顿路径 (HAMPATH)NP-完全之后,要证明它的无向版本 UHAMPATHNP-完全的,从 HAMPATH 出发就比从 3SAT 出发简单得多。
💡 [数值示例]
  • 示例:归约链 (Reduction Chain)
  • 起点SAT (布尔可满足性问题) 是 NP-完全的 (库克-莱文定理)。
  • 第1步:我们可以证明 SAT $\le_P$ 3SAT。这样,3SAT 就成了我们工具箱里的第一个成员。
  • 第2步:在本章中,我们将看到如何证明 3SAT $\le_P$ CLIQUE (团问题)。现在 CLIQUE 也被证明是 NP-完全的,可以加入工具箱。
  • 第3步:假设我们现在想证明一个新的问题,叫做“独立集问题 (INDEPENDENT SET)”是 NP-完全的。独立集是指图中的一个点集,其中任意两点之间都没有边。我们可以发现,一个图 G 中大小为 k 的团 (CLIQUE),正好对应于它的补图 $\overline{G}$ (有边变没边,没边变有边) 中大小为 k 的独立集。这个转换非常简单,是多项式时间的。因此,我们可以方便地证明 CLIQUE $\le_P$ INDEPENDENT SET,而不需要再费力地从 3SAT 开始构造。
⚠️ [易错点]
  1. 归约方向错误:初学者最常犯的错误是搞反归约方向。要证明 B 是 NP-完全的,必须是 $A \le_P B$,其中 A 是已知的 NP-完全问题。这意味着“用 B 的解法器来解决 A”。直观上,这意味着 B 至少和 A 一样难。如果搞成 $B \le_P A$,那只说明 B 不比 A 难,无法证明 B 是 NP-完全的。
  2. 忘记“多项式时间”:归约过程本身必须是高效的,即在多项式时间内完成。如果把问题 A 转换成问题 B 的过程需要指数时间,那么这个归约是无效的。例如,用暴力搜索解决 A,然后把答案编码到 B 的一个简单实例中,这不是一个有效的归约。
📝 [总结]

本段是全节内容的方法论纲领。它明确指出,本节将通过一系列实例来教授证明 NP-完全性的核心技术——多项式时间归约。通用的策略是从经典的 3SAT 问题出发进行归约,但为了证明的便利性,也会利用 NP-完全性的传递性,从其他已被证明的 NP-完全问题进行归约。

🎯 [存在目的]

本段的目的是为读者设定清晰的预期。在深入到复杂的证明细节之前,它先给出了一个高层次的路线图,告诉读者接下来会看到什么(一系列 NP-完全性证明),以及这些证明背后的统一思想是什么(多项式时间归约)。这有助于读者带着一个清晰的框架去理解后续复杂的“小工具 (gadget)”构造和逻辑推导。

[直觉心-模型]

想象你要证明新来的一块石头 “B” 非常坚硬。

  1. 你手里已经有一块公认的、已知最坚硬的石头,叫做 “3SAT 石头”。
  2. 多项式时间归约就像是制造一台机器,这台机器可以在很短的时间内(多项式时间),把任何在 “3SAT 石头” 上刻字的任务,都转化成在 “B 石头” 上刻字的任务。
  3. 如果你能造出这台机器,就说明 “B 石头” 至少和 “3SAT 石头” 一样坚硬。因为如果 “B 石头” 很软(很容易刻字),你就可以通过你的机器,间接地在 “3SAT 石头” 上轻松刻字了,这与 “3SAT 石头” 是最坚硬的这一事实相矛盾。
  4. 因此,证明 $A \le_P B$ 就好比是建造了这样一台“任务转换机”。
  5. 本段还提到,有时我们会发现另一块已经被证明和 “3SAT 石头” 一样硬的石头 “C”,从 “C” 改造任务到 “B” 更方便,我们也可以这么做。
💭 [直观想象]

你是一名特工,你的任务是证明一个代号为“CLIQUE”的新锁和传说中最难破解的“3SAT 锁”一样复杂。

  1. 多项式时间归约就是你的行动计划:你设计一个方案,能把任何一个“3SAT 锁”的实例,在很短的时间内,重新组装成一个“CLIQUE 锁”的实例。
  2. 并且,这个组装方案必须保证:原来的“3SAT 锁”能被打开,当且仅当新组装的“CLIQUE 锁”能被打开。
  3. 如果你成功了,就意味着任何能开“CLIQUE 锁”的人,也一定能通过你的方案打开任何“3SAT 锁”。这说明“CLIQUE 锁”的破解难度至少和“3SAT 锁”一样高。
  4. 本段说,我们的主要策略就是学习如何设计这种“锁的重组方案”,并且主要从“3SAT 锁”开始学。但学会之后,我们也可以从其他同样复杂的锁(如“顶点覆盖”锁)开始重组,只要更方便就行。

1.3. 归约中的“小工具”

📜 [原文3]

在构建从 3SAT 到某种语言的多项式时间归约时,我们寻找该语言中可以模拟布尔公式中的变量和子句的结构。这些结构有时被称为小工具(gadgets)。例如,在从 3SATCLIQUE 的归约中(定理 7.32),单个节点模拟变量,三元组节点模拟子句。单个节点可以属于或不属于团,对应于变量可以为真或为假。每个子句必须包含一个被赋值为真的文字。相应地,每个三元组必须包含一个团中的节点(以便达到目标大小)。定理 7.32 的以下推论表明 CLIQUENP-完全的。

📖 [逐步解释]

这段话介绍了 NP-完全性归约证明中的一个核心思想和术语:“小工具 (gadget)”。

  1. “在构建从 3SAT 到某种语言的多项式时间归约时,我们寻找该语言中可以模拟布尔公式中的变量和子句的结构。”
    • 这是归约构造的核心思路。我们要从 3SAT 归约,就要在新问题中“复刻”出 3SAT 的核心元素。
    • 3SAT 公式的核心元素是什么?就是变量 (variables)子句 (clauses)
    • 变量可以取值为“真”或“假”,这是一个二元选择。
    • 子句是由三个文字(变量或其否定)通过“或”连接起来的,整个公式要求所有子句都必须为“真”。
    • 因此,归约的关键就在于,在目标问题(例如 CLIQUE 问题)的实例(例如一个图)中,找到一些局部结构,用这些结构来一一对应地模仿 3SAT 的变量和子句,并确保它们之间的相互作用能准确反映原公式的逻辑约束。
  2. “这些结构有时被称为小工具(gadgets)。”
    • 这里给出了一个非常形象的术语。Gadget,即“小装置”或“小工具”,就是指我们为了模拟 3SAT 的某个特定部分(如一个变量或一个子句)而在目标问题中精心设计的局部构造。
    • 变量小工具 (Variable Gadget):它的作用是模拟一个布尔变量的“真/假”二选一。它必须具有某种“双稳态”特性。
    • 子句小工具 (Clause Gadget):它的作用是确保对应的子句必须被满足。它通常与相关的变量小工具有联系,并施加一个约束,即这些变量小工具中至少有一个要处于“满足该子句”的状态。
  3. “例如,在从 3SAT 到 CLIQUE 的归约中(定理 7.32),单个节点模拟变量,三元组节点模拟子句。”
    • 这里用一个(虽然在原文中未详细展开的)例子来具体说明 gadget 的概念。这个例子与后续的 VERTEX-COVER 归约中的 gadget 不同,是另一种思路。在 3SATCLIQUE 的归约中:
    • 变量模拟:对于每个变量 $x_i$,我们不是用一个结构,而是为它的每个出现(在不同子句中)创建一个节点。
    • 子句模拟:我们将属于同一个子句的文字对应的节点组织在一起,但不在它们之间连边。
    • 约束:我们在两个节点之间连边,当且仅当它们分别代表的文字是相容的(即,它们可以同时为真)。这有两层意思:1) 它们属于不同的子句。2) 它们不是一对矛盾的文字(如 $x_i$$\overline{x_i}$)。
    • 目标:如果公式有 $k$ 个子句,那么寻找一个大小为 $k$团 (CLIQUE) 就等价于为每个子句挑选一个为真的文字,且这些选择互不矛盾。
  4. “单个节点可以属于或不属于团,对应于变量可以为真或为假。每个子句必须包含一个被赋值为真的文字。相应地,每个三元组必须包含一个团中的节点(以便达到目标大小)。”
    • 这段话似乎将 CLIQUE 的归约和 VERTEX-COVER 的归约中的概念有所混淆,或者是在用一个更泛化的方式来描述。让我们聚焦于 gadget 的核心思想:
    • 状态对应:“属于或不属于团” 对应 “真或假”。这是 gadget 的核心功能,即将目标问题的解的某种属性(一个节点是否在团里,一条边是否被覆盖)映射到源问题(3SAT)的解的属性(一个变量是真是假)。
    • 约束对应:“每个子句必须满足” 对应 “每个子句小工具必须满足某个结构要求”。例如,在 VERTEX-COVER 归约中,是要求子句小工具的内部边必须被覆盖。在 CLIQUE 归约中,是要求最终选出的 $k$ 个节点中,必须每个子句都贡献一个。
  5. “定理 7.32 的以下推论表明 CLIQUE 是 NP-完全的。”
    • 这句是承上启下,说明在证明 CLIQUENP 成员之后,只要完成了从 3SATCLIQUE多项式时间归约,就可以得出 CLIQUENP-完全的结论。
💡 [数值示例]

让我们以 3SAT顶点覆盖 (VERTEX-COVER) 的归约为蓝本,来说明 gadget 的具体构造(这比原文模糊的例子更清晰,也与后面的内容更一致)。

假设我们有 3SAT 公式 $\phi = (x_1 \lor \overline{x_2} \lor x_3)$

  • 变量小工具 (Variable Gadgets)
  • 为变量 $x_1$ 创建两个节点,分别标记为 $v_{1,T}$$v_{1,F}$,并在它们之间连接一条边。这个结构就是一个 变量小工具。要覆盖这条边,我们必须选择 $v_{1,T}$$v_{1,F}$ 加入顶点覆盖集。这完美地模拟了变量 $x_1$ 必须被赋值为“真”或“假”的二元选择。
  • 同样为 $x_2$ 创建 $v_{2,T}, v_{2,F}$ 和边,为 $x_3$ 创建 $v_{3,T}, v_{3,F}$ 和边。
  • 子句小工具 (Clause Gadget)
  • 为子句 $c_1 = (x_1 \lor \overline{x_2} \lor x_3)$ 创建一个由三个节点 $u_{1,1}, u_{1,2}, u_{1,3}$ 组成的三角形(三条边)。这是一个 子句小工具。要覆盖这三条边,我们至少需要选择其中两个节点。
  • 连接小工具
  • 现在连接变量和子句。因为子句 $c_1$ 包含 $x_1$,我们就连接 $v_{1,T}$$u_{1,1}$
  • 因为子句 $c_1$ 包含 $\overline{x_2}$,我们就连接 $v_{2,F}$$u_{1,2}$。(注意是 F,代表 $\overline{x_2}$ 为真)。
  • 因为子句 $c_1$ 包含 $x_3$,我们就连接 $v_{3,T}$$u_{1,3}$

这个由各种节点和边构成的复杂结构,就是 VERTEX-COVER 问题的实例。Gadget 就是指其中的“变量对”和“子句三角形”这些有特定功能的模块化组件。

⚠️ [易错点]
  1. 小工具设计不当Gadget 的设计是归约的艺术所在,也是最容易出错的地方。一个好的 gadget 必须忠实地、无歧义地模拟源问题的行为。
  2. 不完备:如果 gadget 的某种状态在源问题中没有对应,或者源问题的某种状态在 gadget 中无法体现,那么归约就是失败的。
  3. 有副作用:如果 gadget 之间的交互产生了意料之外的约束,破坏了模拟的纯粹性,归约也会失败。例如,两个不相关的变量的 gadget 在图中产生了不应有的联系。
  4. 混淆不同归约的 Gadget:不同的归约(如 3SATCLIQUE3SATVERTEX-COVER)会使用完全不同的 gadget。学习时必须清楚地区分,不能张冠李戴。原文的例子本身就有点模糊,容易让人和后面 VERTEX-COVERgadget 混淆。
📝 [总结]

本段引入了在 NP-完全归约证明中一个至关重要的概念——小工具 (gadget)Gadget 是在目标问题实例中,为了模拟源问题(通常是 3SAT)的核心组成部分(变量和子句)而精心设计的局部结构。通过将变量的二元选择和子句的满足条件,转化为 gadget 必须满足的某种属性(如节点是否被选中,边是否被覆盖),从而建立起两个问题之间的等价性。这个思想是理解和构造归约的关键。

🎯 [存在目的]

本段的目的是将抽象的“归约”思想具体化、工具化。它给出了一个可操作的思路:不要把归约看作一个整体的、天马行空的变换,而是看作一个模块化的“翻译”过程。你需要为源语言的每个“词汇”(变量、子句)找到目标语言中对应的“短语”(gadget),然后把它们组装起来。这使得复杂的归约构造过程变得更有条理、更易于理解和设计。

🧠 [直觉心智模型]

想象你在用乐高积木(目标问题,如)来搭建一个能工作的布尔电路(源问题,3SAT)。

  1. 变量小工具:你设计了一种乐高组合(例如,一个跷跷板结构),它只有两种稳定的状态:左边翘起或右边翘起。这正好可以代表一个变量的“真”或“假”。
  2. 子句小工具:你又设计了另一种乐高组合(例如,一个由三个开关控制的灯),只有当三个开关中至少有一个被按下时,灯才会亮。这代表一个子句必须被满足。
  3. 连接:然后你用乐高杆件把代表变量的跷跷板和代表子句的开关灯连接起来。例如,如果子句里有 $x_i$,你就把 $x_i$ 跷跷板“真”的那一端连到子句灯的一个开关上。
  4. 整个归约过程,就是用这些设计好的“乐高小工具”把整个 3SAT 电路图复刻出来。问原来的电路能否被满足,就等价于问你搭建的这个复杂的乐高模型能否达到某个整体目标(例如,让所有的灯都亮起来)。
💭 [直观想象]

你是一个电影导演,要把一部小说(3SAT 公式)改编成电影(例如,一个关于寻找哈密顿路径的迷宫冒险故事)。

  1. 小说里有一个主角叫“变量 $x_1$”,他有两个选择:去“真理之城”或去“谎言之城”。
  2. 变量小工具:你在电影里设计了一个特殊的“菱形岔路口”,冒险者从一端进入,只能选择两条路中的一条(例如,靠上走或靠下走)穿过它,这分别对应主角选择去“真理之城”或“谎言之城”。
  3. 小说里有一个情节是“主角必须打开三个锁中的一个才能过关”(一个子句)。
  4. 子句小工具:你在电影里设计了一个“神庙”,冒险者必须拜访这个神庙才能继续前进。
  5. 连接:你设计了从“菱形岔路口”的不同路径到“神庙”的隐藏通道。例如,如果主角选择走“真理之城”那条路,就会有一条捷径可以让他顺路访问某个神庙。
  6. 整个归约过程,就是把小说中的所有人物选择和情节要求,都用电影场景中的“岔路口”、“神庙”和“隐藏通道”这些“小工具”来表现出来。小说是否有一个皆大-欢喜的结局(公式可满足),就等价于电影中的冒险者是否有一条能走遍所有必经之地(如所有神庙)的通关路线(哈密顿路径)。

1.4. CLIQUE 的 NP-完全性

📜 [原文4]

推论 7.43

CLIQUENP-完全的。

📖 [逐步解释]

这部分内容非常简洁,它是一个推论的陈述。

  1. “推论 7.43”: 这是一个编号,表明这个结论是基于前面某个定理(这里是未详细展开的定理 7.32)直接得出的。在数学和理论著作中,“推论 (Corollary)” 是指一个可以从前面的定理或证明中轻易、直接地推导出来的结论,无需复杂的新证明。
  2. “CLIQUE 是 NP-完全的。”: 这是本节的核心结论。
    • CLIQUE (团问题):输入是一个图 $G$ 和一个整数 $k$,问题是 $G$ 中是否存在一个大小为 $k$是图中的一个完全子图,即子图中的任意两个节点之间都有边相连。
    • NP-完全 (NP-complete):意味着 CLIQUE 问题同时满足两个条件:
  3. CLIQUE $\in$ NP:这个问题属于 NP 类。这一点比较容易理解。如果你给我一个图 $G$ 和一个由 $k$ 个节点组成的集合,我可以在多项式时间内验证这个集合是否构成一个。我只需要检查两件事:这个集合的大小是不是 $k$,以及集合中任意一对节点之间是否存在边。这个验证过程的复杂度大约是 $O(k^2 \cdot |E|)$ 或更优,是多项式级别的。
  4. CLIQUENP-难 (NP-hard):任何 NP 问题都可以多项式时间归约CLIQUE。正如前面几段所讨论的,我们通过证明一个已知的 NP-完全问题(如 3SAT)可以归约到 CLIQUE(即 3SAT $\le_P$ CLIQUE)来证明这一点。
    • 这个推论的成立,是基于“定理 7.32”已经完成了 3SAT $\le_P$ CLIQUE 的证明。因此,结合 CLIQUE $\in$ NP,我们就能得出 CLIQUENP-完全的最终结论。
💡 [数值示例]
  • 示例1:一个有团的图
  • 输入:图 $G$ 有节点 {1, 2, 3, 4, 5},边为 {(1,2), (1,3), (1,4), (2,3), (2,4), (3,4), (4,5)}。$k=4$
  • 问题$G$ 中是否存在大小为 4 的团?
  • :是。节点集合 {1, 2, 3, 4} 就是一个大小为 4 的团,因为其中任意两个节点之间都有边。
  • 验证:给我 {1, 2, 3, 4} 这个解,我检查:(1,2)有边,(1,3)有边,(1,4)有边,(2,3)有边,(2,4)有边,(3,4)有边。所有 6 对节点之间都有边。验证通过。这说明了 CLIQUE $\in$ NP
  • 示例2:一个没有团的图
  • 输入:同样的图 $G$$k=5$
  • 问题$G$ 中是否存在大小为 5 的团?
  • :否。因为节点 5 只和节点 4 相连,它不可能与 1, 2, 3 同时构成团。
  • NP-完全的含义:对于这个小图,我们很容易看出答案。但当图有成千上万个节点时,要找出是否存在一个例如大小为 100 的团,就没有已知的快速通用方法了。暴力搜索需要检查所有大小为 100 的节点组合,这是一个天文数字。CLIQUENP-完全的,意味着(在 P ≠ NP 的假设下)这样的快速通用方法不存在。
⚠️ [易错点]
  1. 推论的依赖性:必须理解这是一个“推论”,它的正确性完全依赖于前文(定理 7.32)已经成功证明了 3SAT $\le_P$ CLIQUE。如果那个证明有误,这个推论也就不成立。
  2. CLIQUE vs 最大 CLIQUECLIQUE 问题是一个判定问题(回答“是”或“否”)。它还有一个兄弟版本,叫做“最大团问题 (Maximum Clique Problem)”,这是一个优化问题,要求找到图中最大的那个团。这两个问题密切相关,最大团问题是 NP-难的。通常说的 CLIQUE 是指判定版本。
📝 [总结]

本段以推论的形式,明确宣告了 CLIQUE (团问题) 是一个 NP-完全问题。这是计算复杂性理论中的一个里程碑式的结论。它意味着寻找图中是否存在特定大小的完全子图,在本质上和解决 3SAT 问题一样困难,并且(在 P ≠ NP 假设下)不存在通用的高效算法。

🎯 [存在目的]

本段的目的是将 CLIQUE 问题正式加入到我们的“已知 NP-完全问题工具箱”中。在证明了 3SATNP-完全性之后,CLIQUE 是我们通过归约方法拿下的第一个重要“战利品”。从现在开始,当我们需要证明其他图论相关问题是 NP-完全的时,我们就可以选择从 CLIQUE 出发进行归约,这往往比从 3SAT 出发更直观、更方便。

🧠 [直觉心智模型]

回到“NP-完全山脉”的比喻。

  1. 库克和莱文首先发现了这座险峻山脉,并确认了第一座无法攀登的山峰,叫做“SAT 峰”。
  2. 然后人们发现,从“SAT 峰”可以很容易地修一条路到旁边的“3SAT 峰”,说明它也一样高,无法攀登。
  3. 本段的“定理 7.32”就好比是探险家们又从“3SAT 峰”修建了一条栈道,通向了一座新的、看起来完全不同的山峰,叫做“CLIQUE 峰”。
  4. 这个“推论 7.43”就是探险队在“CLIQUE 峰”顶插上的一面旗帜,上面写着:“此峰已被证实为‘NP-完全山脉’的一部分,无法从底部攀登。”
  5. 从此以后,其他探险队想探索附近的山峰时,就可以直接从“CLIQUE 峰”出发,而不用再回到遥远的“3SAT 峰”了。
💭 [直观想象]

想象一个“已知犯罪团伙名单”,这个名单上的团伙都是最顶级的、最难抓捕的,代号为“NP-完全”。

  1. 一开始,名单上只有 FBI 认定的始祖级团伙 “3SAT”。
  2. 一个侦探(卡普)通过卧底调查,发现了一个新的街头帮派 “CLIQUE”。他写了一份详细的报告(定理 7.32),报告证明了任何 “3SAT” 团伙策划的犯罪活动,都可以通过一套固定的流程,转化成 “CLIQUE” 帮派的一次行动,并且前者的成败完全取决于后者的成败。
  3. “推论 7.43” 就是局长看完报告后下的最终定论:“把‘CLIQUE’也加入‘NP-完全’犯罪团伙名单!它的危险等级和‘3SAT’一样高。”
  4. 从此,其他侦探在调查新帮派时,如果发现新帮派和“CLIQUE”有直接联系,就可以直接引用这份报告,快速将其也列为“NP-完全”团伙,而无需再从最原始的“3SAT”开始调查了。

22. 从3SAT到顶点覆盖(Vertex Cover)的归约

注意:原文此处开始的文字描述的是从 3SAT顶点覆盖 (VERTEX-COVER) 问题的归约,但标题和前面的例子却是指向 CLIQUE。这是一个常见的教材编写中的混淆或笔误。接下来的解释将严格按照原文的 文字内容 (即 VERTEX-COVER 的归约) 进行,尽管它被错误地放在了 CLIQUE 的标题之下。我们将把这个归约视为对 VERTEX-COVER 问题的 NP-完全性证明。顶点覆盖问题是:给定一个图 $G$ 和一个整数 $k$,是否存在一个大小为 $k$ 的节点集合,使得图中每条边都至少与该集合中的一个节点相连。

2.1. 子句的小工具

📜 [原文5]

子句的小工具(gadgets)稍微复杂一些。每个子句小工具是一个三元组节点,它们用子句的三个文字进行标记。这三个节点相互连接,并连接到变量小工具中具有相同标记的节点。因此,$G$ 中出现的节点总数为 $2m+3l$,其中 $\phi$$m$ 个变量和 $l$ 个子句。令 $k$$m+2l$

📖 [逐步解释]

这段话描述了用于 顶点覆盖 归约的 子句小工具 (Clause Gadget) 的构造,以及整个图的规模。

  1. “子句的小工具(gadgets)稍微复杂一些。”
    • 这句话暗示之前已经讨论过一个相对简单的 gadget,即 变量小工具。一个典型的 变量小工具 是为每个变量 $x_i$ 创建两个节点(比如标记为 $x_i$$\overline{x_i}$)并在它们之间连一条边。要覆盖这条边,必须选两者之一,这模拟了变量的真假赋值。
  2. “每个子句小工具是一个三元组节点,它们用子句的三个文字进行标记。”
    • 这里开始描述 子句小工具 的内部结构。对于 3SAT 公式中的每一个子句 $c_j$,我们都创建一个对应的 gadget
    • 这个 gadget 由三个节点组成。为了方便理解,我们可以将这三个节点与子句中的三个文字一一对应。例如,如果子句是 $(x_1 \lor \overline{x_2} \lor x_3)$,那么这三个节点就可以想象成代表 $x_1$ 在此子句中的出现、$\overline{x_2}$ 在此子句中的出现、以及 $x_3$ 在此子句中的出现。
  3. “这三个节点相互连接...”
    • 这是 子句小工具 内部结构的关键。这三个节点构成一个三角形(一个大小为 3 的团)。这意味着它们之间有三条边。
    • 这个结构的作用是什么?在一个顶点覆盖问题中,要覆盖一个三角形的三条边,我们至少需要选择其中的两个节点。选择一个节点只能覆盖与其相连的两条边,还剩下一条对边未被覆盖。因此,这个三角形结构强制要求我们必须从这三个节点中,至少选出两个放入顶点覆盖集中。
  4. “...并连接到变量小工具中具有相同标记的节点。”
    • 这描述了 子句小工具变量小工具 之间的连接方式,这是整个归约的核心所在,它建立了逻辑约束。
    • 假设我们已经为每个变量 $x_i$ 创建了 变量小工具,即两个节点 $v_i$ (代表 $x_i$ 为真) 和 $\overline{v_i}$ (代表 $x_i$ 为假),以及它们之间的边。
    • 现在,如果一个子句 $c_j$ 包含文字 $x_1$,我们就将 $c_j$子句小工具 中代表 $x_1$ 的那个节点,与 变量小工具 $x_1$ 中的 $v_1$ 节点连接起来。
    • 如果子句 $c_j$ 包含文字 $\overline{x_2}$,我们就将 $c_j$子句小工具 中代表 $\overline{x_2}$ 的那个节点,与 变量小工具 $x_2$ 中的 $\overline{v_2}$ 节点连接起来。
    • 这个连接的作用是传递“赋值”信息。如果一条边 $(u, v)$ 要被覆盖,我们可以选择 $u$,也可以选择 $v$。这个连接边建立了一个选择的关联:我们可以通过选择 变量小工具 中的节点来帮助覆盖这条连接边,从而影响我们在 子句小工具 中的选择。
  5. “因此,$G$ 中出现的节点总数为 $2m+3l$,其中 $\phi$$m$ 个变量和 $l$ 个子句。”
    • 这里在计算整个构造出来的图 $G$ 的节点总数。
    • 变量小工具:每个变量 $x_i$ (共 $m$ 个) 对应两个节点。所以总共有 $2m$ 个变量节点。
    • 子句小工具:每个子句 $c_j$ (共 $l$ 个) 对应三个节点。所以总共有 $3l$ 个子句节点。
    • 总节点数 = 变量节点数 + 子句节点数 = $2m + 3l$
  6. “令 $k$$m+2l$。”
    • 这里定义了顶点覆盖问题实例的目标大小 $k$。这个 $k$ 的取值是精心设计的,是整个归约能够成功的关键。
    • $k = m + 2l$ 的含义是什么?
    • $m$:来自 $m$变量小工具。每个变量小工具是一条边,至少需要 1 个节点来覆盖。为了覆盖所有 $m$变量小工具内部的边,我们总共至少需要 $m$ 个节点。我们计划恰好选择 $m$ 个节点,即每个变量二选一。
    • $2l$:来自 $l$子句小工具。每个子句小工具是一个三角形,至少需要 2 个节点来覆盖其内部的三条边。为了覆盖所有 $l$子句小工具内部的边,我们总共至少需要 $2l$ 个节点。我们计划恰好选择 $2l$ 个节点。
    • 这个目标值 $k$ 是一个“紧张”的预算。它恰好等于我们在每个小工具内部为了满足覆盖要求而必须选择的节点数量之和。这个“不多不少”的预算,正是强制逻辑关系成立的关键。
💡 [数值示例]
  • 示例
  • 3SAT 公式 $\phi$$(x_1 \lor \overline{x_2}) \land (x_2 \lor x_3)$
  • 参数:这里我们用一个包含两个文字的子句为例,虽然是 2-SAT,但足以说明构造。
  • 变量数 $m = 3$ ($x_1, x_2, x_3$)。
  • 子句数 $l = 2$ ($c_1, c_2$)。
  • 节点总数$2m + 2l = 2*3 + 2*2 = 10$。(注意这里每个子句是2个文字,所以是 $2m+2l$)。如果严格按原文的 3-SAT,假设 $c_1=(x_1 \lor \overline{x_2} \lor x_1)$$c_2=(x_2 \lor x_3 \lor x_2)$,则 $m=3, l=2$
  • 变量节点 (6个): $v_1, \overline{v_1}, v_2, \overline{v_2}, v_3, \overline{v_3}$
  • 子句节点 (6个): 属于 $c_1$$u_{1,1}, u_{1,2}, u_{1,3}$;属于 $c_2$$u_{2,1}, u_{2,2}, u_{2,3}$
  • 总节点数$2*3 + 3*2 = 12$
  • 顶点覆盖目标大小 k
  • $k = m + 2l = 3 + 2*2 = 7$
  • 构造出的图 G 的 k 值的意义
  • 我们需要在 $G$ 中找到一个大小为 7 的顶点覆盖集。
  • 这个预算的分配是固定的:必须从 3 个变量小工具中各选 1 个节点(共 3 个),从 2 个子句小工具中各选 2 个节点(共 4 个)。总共 $3+4=7$ 个。
  • 任何其他的选择方案(比如在某个变量小工具中选了 2 个节点,或者在某个子句小工具中只选了 1 个节点)都会导致预算超支,或者无法覆盖所有边。这个“紧张的预算”是证明的关键。
⚠️ [易错点]
  1. k 值的计算$k$ 的值是归约成功的核心,必须精确计算并理解其构成。$k=m+2l$ 这个公式是针对 3SAT 到 VERTEX-COVER 归约的特定设计,不能滥用到其他归约中。
  2. 小工具的命名:为了清晰,最好使用一致且有意义的命名法来标记小工具的节点,例如用 $v$ 表示变量节点,用 $u$ 表示子句节点,并用下标指明其所属的变量/子句和具体代表的文字。
  3. 原文的混淆:再次强调,这部分描述的是 VERTEX-COVER 的归约,而非 CLIQUE。如果强行理解为 CLIQUE,整个逻辑都是不通的。例如,在 CLIQUE 中,我们是寻找密集连接的子图,而 VERTEX-COVER 是寻找能“打散”所有边的节点集,两者目标相反。
📝 [总结]

本段详细阐述了 3SAT 到 VERTEX-COVER 归约中 子句小工具 的构造方法及其与 变量小工具 的连接方式。每个子句被转换为一个三角形节点组,这种结构强制要求至少选择两个节点才能覆盖其内部。整个图的节点数被确定为 $2m+3l$,而顶点覆盖的目标大小 $k$ 被精巧地设定为 $m+2l$。这个紧凑的预算 $k$ 强制要求任何有效的顶点覆盖解都必须在每个变量小工具中恰好选择一个节点,在每个子句小工具中恰好选择两个节点,从而为模拟布尔逻辑奠定了基础。

🎯 [存在目的]

本段的目的是具体化归约的构造细节,特别是 子句小工具 的设计和图的整体参数设定。它展示了如何将 3SAT 的一个核心约束(子句必须被满足)转化为图论问题的一个结构性约束(三角形的边必须被覆盖)。通过设定精确的节点总数和目标覆盖数 $k$,它为后续的正确性证明(即证明公式可满足当且仅当图存在大小为 $k$ 的顶点覆盖)铺平了道路。

[直觉心-模型]

想象一个安保系统设计问题。

  1. 变量小工具:你有 $m$ 个房间,每个房间都有一个前门和一个后门(节点 $v_i, \overline{v_i}$)。前后门之间有一条红外线(边 $(v_i, \overline{v_i})$)。你必须在每个房间的前门或后门之一安装一个摄像头,才能监控到这条红外线。你的预算是 $m$ 个摄像头。
  2. 子句小工具:你有 $l$ 个保险柜。每个保险柜由一个三角形的玻璃柜保护(节点 $u_{j,1}, u_{j,2}, u_{j,3}$ 及它们之间的三条边)。要确保玻璃柜的所有三面都被监控到,你必须在三个角中的至少两个角上安装摄像头。你的预算是每个保险柜 2 个摄像头。
  3. 连接:每个保险柜都与某些房间的门有特定的关联。例如,保险柜 $j$ 的第一个角($u_{j,1}$)和房间 $i$ 的前门($v_i$)之间也有一条红外线。
  4. 总预算 k:你的总预算是 $k = m + 2l$ 个摄像头。
  5. 问题:能否用这 $k$ 个摄像头,监控到所有的红外线(图的所有边)?
  6. 本段的设计就表明,你必须严格按照“每个房间1个,每个保险柜2个”的方式来分配摄像头。你没有额外的摄像头去处理连接房间和保险柜的那些红外线。唯一的办法是,你在房间里选择的那个摄像头,正好也能顺便监控到连接保险柜的红外线。这就模拟了变量的赋值如何满足子句。
💭 [直观想象]

你是一个派对策划人,正在安排座位。

  1. 变量小工具:有 $m$ 对夫妇(变量 $x_i$)。每对夫妇(节点 $v_i, \overline{v_i}$)之间关系紧张,不能同时请来,必须二选一。这构成了一个约束(边)。
  2. 子句小工具:有 $l$ 张圆桌,每张桌子只有三个座位(子句 $c_j$)。这三个座位上的人互相认识,形成一个小圈子(三角形)。
  3. 连接:你有一些额外的安排规则,比如A桌的1号位客人,和B夫妇里的丈夫是好朋友(连接边)。
  4. 总人数 k:你的派对总共只能容纳 $k = m + 2l$ 人。
  5. 目标(顶点覆盖):你需要选出一个大小为 $k$ 的宾客名单,使得所有“关系”(边)都至少有一个人在场。
  6. 推导
  7. 为了满足“夫妇二选一”的约束,你必须从 $m$ 对夫妇中各选一人,这就占了 $m$ 个名额。
  8. 为了让每张圆桌的“小圈子”关系被代表,你需要从每桌的三个座位中至少请来两人,这就占了 $2l$ 个名额。
  9. 你的名额 $k=m+2l$ 刚好用完。
  10. 现在要考虑连接夫妇和餐桌的那些“朋友关系”。由于你没有多余的名额,唯一的办法是,你从夫妇中选出的那个人,正好也是某个餐桌上被邀请的客人,这样他/她一个人就能同时满足两种“关系”。
  11. 一个可满足的赋值,就对应一个成功的派对安排方案。

2.2. 归约图示与示例

📜 [原文6]

例如,如果 $\phi=\left(x_{1} \vee x_{1} \vee x_{2}\right) \wedge\left(\overline{x_{1}} \vee \overline{x_{2}} \vee \overline{x_{2}}\right) \wedge\left(\overline{x_{1}} \vee x_{2} \vee x_{2}\right)$,则归约从 $\phi$ 产生 $\langle G, k\rangle$,其中 $k=8$,且 $G$ 采用下图所示的形式。

图 7.45

$\phi=\left(x_{1} \vee x_{1} \vee x_{2}\right) \wedge\left(\overline{x_{1}} \vee \overline{x_{2}} \vee \overline{x_{2}}\right) \wedge\left(\overline{x_{1}} \vee x_{2} \vee x_{2}\right)$ 产生的图 $G$

📖 [逐步解释]

这部分通过一个具体的 3SAT 公式实例,展示了归约过程生成的图 $G$ 和目标值 $k$然而,这里的图示与前文描述的用于 VERTEX-COVER 的小工具构造完全不同。 这个图示实际上是 3SAT 到 CLIQUE (团) 或者 3SAT 到 INDEPENDENT SET (独立集) 归约中使用的构造。我们在此处对其进行忠实解释,并指出它与前后文的矛盾之处。

让我们先分析这个图示本身代表的归约方法(即 3SAT 到 CLIQUE):

  1. 公式 $\phi$$\phi=\left(x_{1} \vee x_{1} \vee x_{2}\right) \wedge\left(\overline{x_{1}} \vee \overline{x_{2}} \vee \overline{x_{2}}\right) \wedge\left(\overline{x_{1}} \vee x_{2} \vee x_{2}\right)$
    • 这个公式有 2 个变量 ($x_1, x_2$) 和 3 个子句 ($c_1, c_2, c_3$)。
    • 注意子句中可以有重复的文字,例如 $c_1$ 中的 $x_1$$c_2$ 中的 $\overline{x_2}$
  2. $G$ 的构造
    • 节点:图中的节点是根据子句来组织的。每个子句对应一组节点,节点数量等于子句中文字的数量。
    • $c_1 = (x_1 \lor x_1 \lor x_2)$ 对应图顶部的三个节点,分别标记为 $x_1, x_1, x_2$
    • $c_2 = (\overline{x_1} \lor \overline{x_2} \lor \overline{x_2})$ 对应图中左下角的三个节点,标记为 $\overline{x_1}, \overline{x_2}, \overline{x_2}$
    • $c_3 = (\overline{x_1} \lor x_2 \lor x_2)$ 对应图中右下角的三个节点,标记为 $\overline{x_1}, x_2, x_2$
    • 总共有 $3+3+3=9$ 个节点。
    • :图中边的连接规则是:
    • 规则 A (不同子句):只有当两个节点属于不同的子句时,它们之间才可能有边。属于同一个子句的节点之间(如图中顶部的三个 $c_1$ 节点之间)绝对没有边。
    • 规则 B (不矛盾):如果两个节点属于不同子句,我们检查它们标记的文字是否矛盾。如果不矛盾,则在它们之间连一条边。“不矛盾”意味着它们不是形如 $x_i$$\overline{x_i}$ 的一对。
    • 例如
    • 顶部 $c_1$ 的第一个 $x_1$ 节点,与左下角 $c_2$$\overline{x_2}$ 节点之间有边,因为它们属于不同子句,且 $x_1$$\overline{x_2}$ 不矛盾。
    • 顶部 $c_1$ 的第一个 $x_1$ 节点,与左下角 $c_2$$\overline{x_1}$ 节点之间没有边,因为 $x_1$$\overline{x_1}$ 是矛盾的。
    • 顶部 $c_1$ 的第一个 $x_1$ 节点,与顶部 $c_1$ 的第二个 $x_1$ 节点之间没有边,因为它们属于同一个子句。
  3. 目标值 $k$
    • 原文给出的 $k=8$错误的,并且与 CLIQUE 归约的目标不符。在 3SAT 到 CLIQUE 的归约中,目标 $k$ 值应该等于子句的数量
    • 在这个例子中,有 3 个子句,所以正确的 $k$ 值应该是 $k=3$
    • 归约的目标:证明 $\phi$ 可满足 $\iff$$G$ 中存在大小为 $k=3$团 (CLIQUE)

解释这个 CLIQUE 归约为什们有效:

  • 从可满足赋值到团
  • 假设 $\phi$ 有一个满足赋值,例如 $x_1=$ 真, $x_2=$ 假。
  • 我们为每个子句挑选一个在此赋值下为真的文字。
  • $c_1=(x_1 \lor x_1 \lor x_2)$: $x_1$ 为真,我们选择顶部的一个 $x_1$ 节点。
  • $c_2=(\overline{x_1} \lor \overline{x_2} \lor \overline{x_2})$: $\overline{x_2}$ 为真 (因为 $x_2$ 为假),我们选择左下角的一个 $\overline{x_2}$ 节点。
  • $c_3=(\overline{x_1} \lor x_2 \lor x_2)$: $\overline{x_1}$ 为假,两个 $x_2$ 都为假,这个例子中的赋值无法满足 $c_3$。让我们换一个赋值。
  • 换个赋值:$x_1=$ 假, $x_2=$ 真。
  • $c_1=(x_1 \lor x_1 \lor x_2)$: $x_2$ 为真。我们选择顶部的 $x_2$ 节点。
  • $c_2=(\overline{x_1} \lor \overline{x_2} \lor \overline{x_2})$: $\overline{x_1}$ 为真。我们选择左下角的 $\overline{x_1}$ 节点。
  • $c_3=(\overline{x_1} \lor x_2 \lor x_2)$: $\overline{x_1}$$x_2$ 都为真。我们选择右下角的一个 $x_2$ 节点。
  • 我们选出的三个节点是:来自 $c_1$$x_2$,来自 $c_2$$\overline{x_1}$,来自 $c_3$$x_2$
  • 这三个节点来自不同的子句,并且它们代表的文字 ($x_2$, $\overline{x_1}$) 是相容的。根据我们的构造规则,这三个节点两两之间都有边,因此它们构成一个大小为 3 的团。
  • 从团到可满足赋值
  • 假设我们在 $G$ 中找到了一个大小为 3 的团。
  • 由于团中任意两点都有边,根据构造规则 A,这 3 个节点必须来自 3 个不同的子句,即每个子句恰好贡献一个节点。
  • 根据构造规则 B,这 3 个节点代表的文字不能相互矛盾。
  • 我们就可以构造一个赋值:对于团中选中的节点所代表的文字,将其赋值为真。例如,如果团中的节点是 $x_1, \overline{x_2}, x_3$,我们就令 $x_1=$真, $x_2=$假, $x_3=$真。这个赋值是无矛盾的。
  • 由于每个子句都贡献了一个节点到团中,这意味着每个子句都至少有一个文字在这个赋值下为真。因此,整个公式 $\phi$ 是可满足的。

关于原文中 $k=8$ 的错误分析:

这个 $k=8$ 完全不符合 CLIQUE 归约的逻辑。它看起来更像是前文 VERTEX-COVER 归约中 $k=m+2l$ 公式的误用。对于这个公式 $\phi$$m=2, l=3$。如果套用那个公式,$k=m+2l = 2+2*3 = 8$。这表明作者在写这段时,脑子里想的还是 VERTEX-COVER 的归约,但配的图却是 CLIQUE 归约的图,并且把前者的 $k$ 值错误地安在了后者上,造成了严重的混淆。

📝 [总结]

本段提供了一个将具体 3SAT 公式转化为图 $G$ 的实例。然而,该实例存在严重的不一致性:它展示的图构造方法是用于“3SAT 到 CLIQUE”归约的,但给出的目标值 $k=8$ 却是错误地套用了“3SAT 到 VERTEX-COVER”归约的公式。正确的 CLIQUE 归约目标值应为子句数,即 $k=3$。这个例子如果按照 CLIQUE 归约的正确逻辑来理解(即寻找大小为 3 的团),可以很好地展示归约如何建立公式可满足性与图中是否存在特定大小团之间的等价关系。

🎯 [存在目的]

本段的意图是通过一个具体的、可视化的例子来帮助读者理解归约的构造过程。尽管例子本身存在错误和不一致,但其初衷是好的:将抽象的构造规则应用于一个实际的公式,并画出结果图,让读者能更直观地看到变量和子句是如何“变形”成图中的节点和边的。

🧠 [直觉心智模型]

想象你在组织一个国际会议,有 $l$ 个国家代表团(子句),每个代表团有 3 名代表(节点)。

  1. 规则1:同一个代表团的成员互相看不顺眼,不能同时被选入核心委员会。
  2. 规则2:如果两个不同代表团的代表所持的政治立场(文字,如 $x_i$$\overline{x_i}$)有冲突,他们也不能同时被选入核心委员会。
  3. 建图:你画了一张关系图,只有互相没有矛盾的代表之间才连线。
  4. 目标:你要组建一个大小为 $l$ 的核心委员会(大小为 $k=l$ 的团),要求委员会里人人关系和谐(两两之间都有连线)。
  5. 等价性
  6. 能成功组建这样的委员会 $\iff$ 你可以从每个国家的代表团里各挑一个人,并且这些人的政治立场互不冲突。
  7. 这就等价于,你可以找到一种满足所有政治约束(公式可满足)的方案,让每个国家都有代表“满意”(子句被满足)。
💭 [直观想象]

你正在玩一个拼图游戏。

  1. 原料:给你 3 堆积木(子句),每堆有 3 块,积木上写着 $x_1, \overline{x_2}$ 等标签(文字)。
  2. 连接规则:如果两块积木来自不同堆,并且标签不冲突(不是 $x_i$$\overline{x_i}$),你就可以用一根“磁力棒”(边)把它们连起来。
  3. 目标:你需要在图中找到 3 块积木,它们两两之间都由磁力棒连接(构成一个三角形的团)。
  4. 结论:你能找到这样的一个“磁力三角形”,当且仅当你可以从每堆积木中各拿一块,而这三块积木的标签所代表的逻辑赋值不互相矛盾。这正对应于原布尔公式是可满足的。

2.3. 归约的正确性证明(顶点覆盖版本)

📜 [原文7]

为了证明这个归约是有效的,我们需要证明 $\phi$ 是可满足的当且仅当 $G$ 具有 $k$ 个节点的顶点覆盖。我们从一个满足赋值开始。我们首先将变量小工具中与赋值中真文字对应的节点放入顶点覆盖中。然后,我们选择每个子句中的一个真文字,并将每个子句小工具中剩余的两个节点放入顶点覆盖中。现在我们总共有 $k$ 个节点。它们覆盖了所有边,因为每个变量小工具的边都已明确覆盖,每个子句小工具内部的所有三条边都已覆盖,并且变量小工具和子句小工具之间的所有边也都已覆盖。因此 $G$ 具有 $k$ 个节点的顶点覆盖。

其次,如果 $G$ 具有 $k$ 个节点的顶点覆盖,我们通过构造满足赋值来证明 $\phi$ 是可满足的。顶点覆盖必须包含每个变量小工具中的一个节点和每个子句小工具中的两个节点,以覆盖变量小工具的边和子句小工具内部的三条边。这占据了所有节点,因此没有节点剩余。我们取顶点覆盖中变量小工具的节点,并将相应的文字赋值为 TRUE。这个赋值满足 $\phi$,因为连接变量小工具和每个子句小工具的三条边中的每一条都已覆盖,并且子句小工具中只有两个节点在顶点覆盖中。因此,其中一条边必须由来自变量小工具的节点覆盖,因此该赋值满足相应的子句。

📖 [逐步解释]

这部分是 3SAT 到 VERTEX-COVER 归约的正确性证明的核心。它分为两个方向:($\Rightarrow$) 可满足性推导出顶点覆盖,和 ($\Leftarrow$) 顶点覆盖推导出可满足性。这部分内容完全是基于 VERTEX-COVER 的归约,与上一节的图示无关。

第一部分:证明 $\phi$ 可满足 $\Rightarrow G$ 存在大小为 $k$ 的顶点覆盖

  1. “我们从一个满足赋值开始。”
    • 这是证明的起点。我们假设我们已经有了一个能让公式 $\phi$ 为真的变量赋值方案,例如 $x_1=$真, $x_2=$假, ...
  2. “我们首先将变量小工具中与赋值中真文字对应的节点放入顶点覆盖中。”
    • 这是构建顶点覆盖集 $C$ 的第一步。我们根据已知的满足赋值来选择变量节点。
    • 对于每个变量 $x_i$(共 $m$ 个):
    • 如果 $x_i$ 赋值为真,我们就把代表“真”的节点(我们称之为 $v_i$)放入集合 $C$ 中。
    • 如果 $x_i$ 赋值为假,我们就把代表“假”的节点(我们称之为 $\overline{v_i}$)放入集合 $C$ 中。
    • 经过这一步,我们恰好选择了 $m$ 个节点。这些选择直接覆盖了所有 $m$变量小工具的内部边(即 $(v_i, \overline{v_i})$)。
  3. “然后,我们选择每个子句中的一个真文字,并将每个子句小工具中剩余的两个节点放入顶点覆盖中。”
    • 这是构建顶点覆盖集 $C$ 的第二步,处理子句小工具
    • 因为我们假设 $\phi$ 是可满足的,所以每个子句 $c_j$ 都至少包含一个为真的文字。
    • 我们为每个子句 $c_j$(共 $l$ 个)任意选择一个在当前赋值下为真的文字。假设这个文字是 $L$
    • $c_j$子句小工具(一个由三个节点组成的三角形)中,有一个节点是与代表 $L$ 的变量节点相连的。我们不选这个节点。
    • 我们选择这个三角形中剩下的两个节点,将它们放入集合 $C$
    • 对所有 $l$ 个子句都执行这个操作,我们就向 $C$ 中加入了 $2l$ 个节点。
  4. “现在我们总共有 $k$ 个节点。”
    • 我们从变量小工具中选了 $m$ 个节点,从子句小工具中选了 $2l$ 个节点。
    • 集合 $C$ 的总大小为 $m + 2l$,这正好是我们预设的目标值 $k$
  5. “它们覆盖了所有边...”
    • 现在需要验证我们选出的这 $k$ 个节点是否构成了 $G$ 的一个顶点覆盖,即是否图中的每一条边都至少有一个端点在 $C$ 中。图中的边有三类:
    • 变量小工具内部的边:形如 $(v_i, \overline{v_i})$。我们对每个变量都选择了 $v_i$$\overline{v_i}$ 中的一个,所以这些边肯定被覆盖了。
    • 子句小工具内部的边:每个子句小工具是三角形,有三条边。我们选择了其中的两个节点,这两个节点必然覆盖了这三条边。
    • 连接变量和子句的边:这是最关键的部分。考虑连接变量小工具和子句小工具 $c_j$ 的一条边 $(v, u)$,其中 $v$ 在变量小工具中, $u$ 在子句小工具中。
    • 根据我们的选择规则(第3步),我们特意在每个子句 $c_j$ 中找到了一个真文字 $L$,并且没有选择与 $L$ 对应的那个子句节点 $u_L$
    • 那么连接到 $u_L$ 的那条边 $(v_L, u_L)$ 是如何被覆盖的呢?
    • 因为 $L$ 是真文字,所以根据我们的规则(第2步),它对应的变量节点 $v_L$ 一定被选入了集合 $C$
    • 因此,这条连接边被来自变量小工具的节点 $v_L$ 覆盖了。
    • 对于子句小工具中其他的连接边,它们的子句端节点已经被我们选入 $C$ 了,所以它们也被覆盖了。
  6. “因此 $G$ 具有 $k$ 个节点的顶点覆盖。”
    • 我们成功地用一个满足赋值构造出了一个大小为 $k=m+2l$ 的顶点覆盖。证明了这一半。

第二部分:证明 $G$ 存在大小为 $k$ 的顶点覆盖 $\Rightarrow \phi$ 可满足

  1. “如果 $G$ 具有 $k$ 个节点的顶点覆盖,我们通过构造满足赋值来证明 $\phi$ 是可满足的。”
    • 这是反方向的证明。我们假设已经找到了一个大小为 $k=m+2l$ 的顶点覆盖集 $C$。我们要利用这个 $C$ 来找出一个能满足 $\phi$ 的变量赋值。
  2. “顶点覆盖必须包含每个变量小工具中的一个节点和每个子句小工具中的两个节点...”
    • 这是一个关键的结构性断言。为什么必须这样?
    • 变量小工具$m$ 条独立的边(它们之间不共享节点),要覆盖这 $m$ 条边,你至少需要 $m$ 个节点。
    • 子句小工具$l$ 个独立的三角形,要覆盖这 $l$ 个三角形内部的所有 $3l$ 条边,你至少需要 $2l$ 个节点(每个三角形至少2个)。
    • 覆盖这两部分内部的边总共就需要至少 $m+2l = k$ 个节点。
    • 而我们的总预算恰好就是 $k$。这意味着我们没有丝毫浪费的余地。为了用恰好 $k$ 个节点覆盖所有边,我们必须
    • 在每个变量小工具中恰好选择 1 个节点。
    • 在每个子句小工具中恰好选择 2 个节点。
    • 任何其他选择方案(比如在某个变量小工具选2个,或某个子句小工具选3个)都会导致节点总数超过 $k$ 才能覆盖所有内部边。
  3. “这占据了所有节点,因此没有节点剩余。”
    • 顶点覆盖集 $C$ 中的所有 $k$ 个节点,都被完美地分配给了 $m$ 个变量小工具和 $l$ 个子句小工具。
  4. “我们取顶点覆盖中变量小工具的节点,并将相应的文字赋值为 TRUE。”
    • 这是构造赋值的方法。我们遍历顶点覆盖集 $C$ 中来自变量小工具的那 $m$ 个节点。
    • 对于每个变量 $x_i$
    • 如果 $C$ 中包含的是 $v_i$(代表“真”的节点),我们就将 $x_i$ 赋值为真。
    • 如果 $C$ 中包含的是 $\overline{v_i}$(代表“假”的节点),我们就将 $x_i$ 赋值为假。
    • 因为每个变量小工具恰好有一个节点在 $C$ 中,所以这个赋值是明确且无矛盾的。
  5. “这个赋值满足 $\phi$...”
    • 现在需要证明这个构造出来的赋值方案确实能让 $\phi$ 为真,即让每个子句 $c_j$ 都为真。
    • 考虑任意一个子句 $c_j$。我们知道它的子句小工具(三角形)中有两个节点在 $C$ 中。这意味着有一个节点 $u$ 不在 $C$ 中。
    • 考虑连接到这个节点 $u$ 的边,它形如 $(v, u)$,其中 $v$ 是某个变量小工具中的节点。
    • 因为 $C$ 是一个顶点覆盖,所以边 $(v, u)$ 必须被覆盖。
    • 我们已经知道 $u$ 不在 $C$ 中,那么覆盖这条边的责任就落在了 $v$ 身上。因此,节点 $v$ 必须$C$ 中。
    • 节点 $v$$C$ 中,意味着什么?根据我们构造赋值的规则,它所代表的那个文字被赋值为真了!
    • 而这个文字,正是子句 $c_j$ 中的一个文字。
    • 所以,我们证明了,对于任意子句 $c_j$,它都至少包含一个被赋值为真的文字。
  6. “因此,$\phi$ 得到满足。”
    • 所有子句都被满足,所以整个公式 $\phi$ 是可满足的。证明了另一半。
📝 [总结]

本段是 3SAT 到 VERTEX-COVER 归约的核心逻辑证明。它完美地展示了两个问题之间的等价性是如何通过精心设计的 gadget 和目标值 $k$ 建立起来的。

  1. 正向证明展示了如何将一个逻辑上的“满足”状态,转化为一个物理结构上的“覆盖”状态。通过在变量和子句 gadget 中做出特定选择,可以构造一个大小恰好为 $k$ 的顶点覆盖。关键在于,变量赋值为真可以“帮助”覆盖与之相连的子句边。
  2. 反向证明则展示了结构上的“最优性”(用最少的节点覆盖)如何强制产生逻辑上的“满足”。大小为 $k$ 的顶点覆盖是一个“紧绷”的解,它没有冗余。这种紧绷性迫使变量节点的选择必须能够满足所有子句,因为子句小工具自身留出了一个“缺口”,这个缺口必须由一个值为“真”的变量节点来填补。
🎯 [存在目的]

这段证明的存在目的,是为“VERTEX-COVERNP-完全的”这个结论提供严格的数学依据。它不是在描述构造,而是在验证这个构造的正确性。这是所有 NP-完全性证明中最关键、最需要严谨逻辑的部分。它展示了归约不仅仅是形式上的转换,更是逻辑等价性的深刻映射。

🧠 [直觉心智模型]

再次回到安保系统模型:$k = m+2l$ 个摄像头。

  1. 正向:假设你知道一个安全的密码组合(满足赋值)。你按照这个密码组合,在对应的门上(变量)安装摄像头。由于密码是正确的,每个保险柜(子句)至少有一个关联的门是“安全”的。你就在这个保险柜的另外两个“不安全”的角上装摄像头。这样一来,你恰好用了 $k$ 个摄像头,并且可以证明所有红外线都被监控到了。因为那些连接“安全”门和保险柜的红外线,被你装在门上的摄像头搞定了。
  2. 反向:假设你找到了一个只用 $k$ 个摄像头的完美布防方案。由于预算太紧张,你分析后发现,这个方案必须是“每个房间门口装1个,每个保险柜角落装2个”。然后你去看每个保险柜,都发现有一个角没装摄像头。连接这个角的红外线怎么办呢?它必须被另一头的——也就是某个房间门口的摄像头——监控到。于是,你记下所有这些“起到了关键作用”的房门,把它们的状态(前门还是后门)组合起来,就得到了那个唯一的、能使整个安保系统成立的密码组合。
💭 [直观想象]

再次回到派对策划模型:$k=m+2l$ 个宾客名额。

  1. 正向:假设你有一份“和谐人际关系”名单(满足赋值),告诉你每对夫妻请谁来能让大家都开心。你按照名单邀请,这就占了 $m$ 个名额。因为关系是和谐的,所以每张桌子(子句)上都至少有一个“关键人物”其伴侣没来。然后你在这张桌子剩下的两个座位上随便邀请两个人填满。这样你恰好用了 $2l$ 个名额来处理桌子。总共 $k$ 个名额,并且你会发现所有“关系”(边)都被满足了。
  2. 反向:假设你有一份大小为 $k$ 的完美宾客名单,它满足了所有的关系。你发现,由于名额太紧张,名单必然是“每对夫妻来一人,每张桌子来两人”的结构。你检查每张桌子,都发现有一个空位。连接这个空位的“朋友关系”怎么办?必然是被另一端——也就是某个夫妻中的来宾——所满足了。你把所有这些“起到了关键作用”的夫妻来宾记录下来,他们的组合(丈夫来还是妻子来)就构成了一份“和谐人际关系”名单,证明这样的和谐关系是可能存在的。

33. 哈密顿路径问题

3.1. 问题定义

📜 [原文8]

哈密顿路径问题

回想一下 哈密顿路径问题 询问输入图是否包含一条从 $s$$t$ 且经过每个节点恰好一次的路径。

📖 [逐步解释]

这部分简单地重申了 哈密顿路径问题 (Hamiltonian Path Problem, HAMPATH) 的定义。

  1. “哈密顿路径问题”: 这是问题的名称。它以爱尔兰数学家威廉·罗恩·哈密顿命名,他研究了相关的问题。
  2. “询问输入图是否包含一条...”: 这说明 HAMPATH 是一个判定问题 (Decision Problem),它的答案是“是”或“否”。它不要求你找出那条路径,只问你是否存在。
  3. “从 $s$$t$: 这是指路径有指定的起点 $s$ 和终点 $t$。这是 HAMPATH 问题的特定版本,有时也称为“$s-t$ 哈密顿路径问题”。有些版本的定义不指定起点和终点,只问图中是否存在任何一条哈密顿路径。指定起点和终点使得问题更具体,也更容易用于归约。
  4. “经过每个节点恰好一次”: 这是哈密顿路径的核心定义。一条路径如果访问了图中的所有节点,并且每个节点都只访问了一次,那么它就是一条哈密顿路径。
    • “所有节点”: 不能有遗漏。如果图有 $V$ 个节点,路径必须包含所有 $V$ 个节点。
    • “恰好一次”: 不能重复访问。路径是一个简单的路径 (simple path),没有环。
💡 [数值示例]
  • 示例1:存在哈密顿路径
  • 输入:一个图 $G$,节点集 $V=\{s, a, b, t\}$,边集 $E=\{(s,a), (a,b), (b,t)\}$。起点为 $s$,终点为 $t$
  • 问题:是否存在从 $s$$t$ 的哈密顿路径?
  • :是。路径 $s \rightarrow a \rightarrow b \rightarrow t$ 经过了所有四个节点,且每个节点恰好一次。
  • 示例2:不存在哈密顿路径
  • 输入:一个图 $G$,节点集 $V=\{s, a, b, t\}$,边集 $E=\{(s,a), (s,b), (a,t), (b,t)\}$(一个菱形)。起点为 $s$,终点为 $t$
  • 问题:是否存在从 $s$$t$ 的哈密顿路径?
  • :否。任何从 $s$$t$ 的路径,例如 $s \rightarrow a \rightarrow t$,都遗漏了节点 $b$。另一条路径 $s \rightarrow b \rightarrow t$ 则遗漏了节点 $a$。你无法在一条路径中同时访问 $a$$b$ 并满足起点终点要求。
  • 示例3:有向图中的哈密顿路径
  • 输入:一个有向图 $G$,节点 $V=\{s, a, b, t\}$,有向边 $E=\{s \to a, a \to b, b \to t, t \to s, a \to t\}$。起点 $s$,终点 $t$
  • :是。路径 $s \to a \to b \to t$ 是一条哈密顿路径。注意,即使图中存在其他边如 $a \to t$,我们也不使用它。
⚠️ [易错点]
  1. 哈密顿路径 vs 欧拉路径:这是一个经典的易混淆概念。
  2. 哈密顿路径:访问每个节点恰好一次。
  3. 欧拉路径:走过每条边恰好一次。
  4. 一个图可能存在其中一种路径,而没有另一种。判断是否存在欧拉路径有简单的充要条件(关于节点度数的奇偶性),属于 P 类问题。而 HAMPATHNP-完全的。
  5. 路径 vs 环
  6. 哈密顿路径:从一个节点开始,到另一个节点结束。
  7. 哈密顿环 (Hamiltonian Cycle):一条哈密顿路径,并且其起点和终点之间也有一条边,从而形成一个闭环。哈密顿环问题 (HAMCYCLE) 也是一个著名的 NP-完全问题,它和 HAMPATH 密切相关,可以相互归约。
📝 [总结]

本段对 哈密顿路径问题 (HAMPATH) 进行了清晰的定义。该问题要求判断一个给定的图中,是否存在一条从指定起点 $s$ 到指定终点 $t$ 的路径,这条路径必须不重不漏地访问图中的每一个节点。这是一个经典的 NP-完全图论问题。

🎯 [存在目的]

本段的目的是为接下来的 NP-完全性证明设定目标。在引入了一个新的复杂证明之前,首先要确保读者对这个问题的定义有清晰、准确的理解。这是任何严格证明的必要前提。接下来的内容将围绕这个定义展开,展示如何将 3SAT 的逻辑结构“编码”到一个图的结构中,使得图是否存在哈密顿路径等价于公式是否可满足。

🧠 [直觉心智模型]

想象一个“一笔画”游戏,但规则不同。

  1. 棋盘:一个图,节点是棋盘上的点,边是连接点的线。
  2. 规则:你需要从起点 $s$ 出发,用一笔画出一条线,这条线必须经过棋盘上所有的点,每个点只能经过一次,最后停在终点 $t$。你不能抬笔,也不能走重复的点。
  3. 问题:这样的画法是否存在?
  4. HAMPATH 问题就是问,对于给定的棋盘和起终点,这个游戏有没有解。
💭 [直观想象]

你是一个游客,想要规划一次城市观光。

  1. 城市地图:一个图,节点是景点,边是连接景点的公交线路。
  2. 你的计划:你计划从酒店(起点 $s$)出发,必须游览完地图上标记的所有景点,每个景点只去一次,最后到达机场(终点 $t$)。
  3. HAMPATH 问题:是否存在这样一条完美的、不走回头路的观光路线?
  4. 对于小城市,你可能一眼就看出来了。但如果是一个有几百个景点的大都市,规划这样一条路线将变得异常困难,这就是 HAMPATH 问题的难点所在。

3.2. HAMPATH 的 NP-完全性

📜 [原文9]

定理 7.46

HAMPATHNP-完全的。

📖 [逐步解释]

这是一个定理的陈述,是本节的一个核心结论。

  1. “定理 7.46”: 这是该定理的编号。
  2. “HAMPATH 是 NP-完全的。”:
    • HAMPATH: 正如刚刚定义的,是在一个图中寻找一条经过所有节点恰好一次的 $s-t$ 路径的判定问题。
    • NP-完全: 这个断言意味着 HAMPATH 问题同时具备两个属性:
  3. HAMPATH $\in$ NP: 这个问题属于 NP 类。这一点很容易证明。如果有人给了你一条声称是哈密顿路径的节点序列(例如 $s, v_1, v_2, ..., t$),你可以在多项式时间内验证它。你需要检查:(a) 路径的起点是 $s$,终点是 $t$;(b) 序列中包含了图的所有节点;(c) 序列中没有重复节点;(d) 序列中相邻的每一对节点之间在图中确实存在一条边。这些检查都可以在多项式时间内完成。
  4. HAMPATH 是 NP-难 (NP-hard): 任何 NP 问题都可以多项式时间归约HAMPATH。接下来的“证明思路”和“证明”部分,就是要通过证明 3SAT $\le_P$ HAMPATH 来证实这一点。
💡 [数值示例]
  • NP-完全的实际意义:
  • 假设你为一个物流公司工作,需要为一架无人机规划一条投送路线,它需要从仓库($s$)出发,访问 $N$ 个客户投送点,然后飞到充电站($t$)。为了节省能源,你希望无人机每个点只访问一次。
  • 这个问题就是一个 HAMPATH 问题的实例。
  • 由于 HAMPATHNP-完全的,当客户数量 $N$ 很大时(比如 50 个),你的公司不应该期望能找到一个软件,在任何情况下都能在几秒钟内计算出是否存在这样一条完美路线。
  • 知道这一点后,公司可能会改变策略,比如:
  • 开发一个近似算法,寻找一条尽可能短的、访问所有客户的路线(这变成了旅行商问题,也是 NP-难的)。
  • 开发一个启发式算法,在大多数实际的城市布局中能快速找到一个不错的解,但不保证在所有奇怪的布局中都有效。
  • 对问题进行限制,例如,如果所有客户都在一条直线上,问题就变得很简单。
⚠️ [易错点]
  1. 有向图 vs 无向图: 这里的 HAMPATH 通常指的是有向图版本(directed HAMPATH),因为归约中构造的图是带方向的。无向图版本 UHAMPATH 也是 NP-完全的,并且可以由有向版本归约而来,后面会讲到。必须分清正在讨论的是哪个版本。
  2. 证明的完备性: 这个定理的陈述只是一个结论。它的成立,完全依赖于后续的、非常复杂的归约证明。在没有看到那个证明之前,我们只是“接受”这个结论。
📝 [总结]

本段以定理的形式,庄重地宣告了 哈密顿路径问题 (HAMPATH)NP-完全的。这意味着它在计算复杂性上属于最难的一类 NP 问题,与 3SATCLIQUEVERTEX-COVER 等问题等价。这个结论对于算法设计和实际应用具有重要的指导意义,它告诉我们不要期望为大规模的 HAMPATH 问题找到通用的高效解法。

🎯 [存在目的]

本段的目的是清晰地提出本节证明的目标。它像一个章节的标题,预告了接下来的长篇证明将要达成的最终结论。通过先给出结论,再展开证明,可以让读者带着明确的目标去阅读和理解复杂的归约构造过程。

🧠 [直觉心智模型]

回到“NP-完全山脉”的比喻。

  1. 前面我们已经通过修建栈道,在“3SAT 峰”和“CLIQUE 峰”上插上了旗帜。
  2. 现在,探险队看上了另一座风格迥异的山峰,叫做“HAMPATH 峰”,这座山峰的挑战是“一笔画问题”。
  3. 这个定理就是探险队立下的军令状:“我们的目标是证明 HAMPATH 峰也和 3SAT 峰一样高,无法攀登。”
  4. 接下来的所有关于菱形、子句节点的复杂构造,都是在修建一条从“3SAT 峰”通往“HAMPATH 峰”的、极其精巧的、带有方向性的空中索道。
💭 [直观想象]

你是一名法官,正在审理一个案子。

  1. 被告HAMPATH 问题。
  2. 指控:它和臭名昭著的黑帮头目“3SAT”是一伙的,属于“NP-完全”犯罪集团。
  3. 证据(属于 NP):检察官首先证明,验证 HAMPATH 的不在场证明(给出一个路径)很容易(多项式时间),所以它符合“NP 成员”的基本特征。
  4. 核心指证(NP-难):检察官(在本案中是卡普或库克/莱文)将要向法庭展示一个复杂的证据链(归约),证明任何“3SAT”策划的犯罪,都可以转化为一个“HAMPATH”的行动。
  5. 定理 7.46 就是最终的判决书:“经审理,HAMPATH 问题 NP-完全罪名成立,即刻生效。”

3.3. 证明思路

📜 [原文10]

证明思路 我们在 7.3 节中证明了 HAMPATH 属于 NP。为了证明每个 NP 问题都可以多项式时间归约到 HAMPATH,我们证明 3SAT 可以多项式时间归约到 HAMPATH。我们给出一种将 3 cnf-公式转换为图的方法,其中哈密顿路径对应于公式的满足赋值。图包含模拟变量和子句的小工具(gadgets)。变量小工具是一个菱形结构,可以通过两种方式遍历,对应于两种真值设置。子句小工具是一个节点。确保路径经过每个子句小工具对应于确保满足赋值中每个子句都得到满足。

📖 [逐步解释]

这部分概述了证明 HAMPATHNP-完全的整体策略和核心创意。

  1. “我们在 7.3 节中证明了 HAMPATH 属于 NP。”
    • 这重申了证明 NP-完全性的两步中的第一步已经完成。验证一个给定的路径是否是哈密顿路径是容易的。
  2. “为了证明每个 NP 问题都可以多项式时间归约到 HAMPATH,我们证明 3SAT 可以多项式时间归约到 HAMPATH。”
    • 这再次明确了证明 NP-难的标准策略:我们不需要把所有的 NP 问题都归约到 HAMPATH,只需要把一个已知的“代表”(NP-完全问题,这里选 3SAT)归约到 HAMPATH 即可。利用 NP-完全的传递性,就足以证明 HAMPATHNP-难度。
  3. “我们给出一种将 3 cnf-公式转换为图的方法,其中哈密顿路径对应于公式的满足赋值。”
    • 这是归约的核心目标:建立“哈密顿路径的存在性”与“公式的可满足性”之间的当且仅当关系。我们要设计的这个转换(从公式到图的算法)必须保证:
    • 如果公式可满足,那么转换出的图中必定存在一条哈密顿路径。
    • 如果图中存在一条哈密顿路径,那么原公式必定是可满足的。
  4. “图包含模拟变量和子句的小工具(gadgets)。”
    • 这里点出了实现上述目标的技术手段,即再次使用“小工具”的思想。我们需要在图中设计出两种不同功能的结构模块。
  5. “变量小工具是一个菱形结构,可以通过两种方式遍历,对应于两种真值设置。”
    • 这是对变量小工具设计的核心创意的首次揭示。
    • 为每个变量 $x_i$ 设计一个“菱形”的子图结构。
    • 这个菱形结构的关键特性是,任何一条想要“穿过”它的哈密顿路径,都只有两种走法。例如,“从左到右”走或者“从右到左”走(原文用“之字形”和“反之字形”更准确地描述了内部走法)。
    • 我们将这两种走法强制与变量的赋值对应起来:走法 A 代表 $x_i$ 为真,走法 B 代表 $x_i$ 为假。这是一个非常漂亮的“二元选择”的物理模拟。
  6. “子句小工具是一个节点。”
    • 子句小工具的设计在这里看起来非常简单:每个子句 $c_j$ 就只对应图中的一个孤零零的节点。
  7. “确保路径经过每个子句小工具对应于确保满足赋值中每个子句都得到满足。”
    • 这是整个归约的“画龙点睛”之笔。
    • 哈密顿路径要求必须经过图中每一个节点。这意味着,路径必须想办法“拜访”到每一个代表子句的节点。
    • 如何拜访?这些子句节点会通过特定的连接边,与变量小工具联系起来。
    • 连接方式的设计将非常精巧,它要保证:只有当某个变量的赋值(即其变量小工具的遍历方式)满足了某个子句时,哈密顿路径才有机会“顺路”去拜访那个子句对应的节点。
    • 因此,“路径必须访问所有子句节点”这个图论上的要求,就被转化为了“赋值必须满足所有子句”这个逻辑上的要求。
💡 [数值示例]
  • 变量小工具的直观想象
  • 想象一条长长的走廊代表变量 $x_i$。走廊里有一排房间。
  • 你可以选择“从上向下”访问这些房间,这代表 $x_i=$ 真。
  • 你也可以选择“从下向上”访问这些房间,这代表 $x_i=$ 假。
  • 但你必须访问完所有房间,并且只能选择一种顺序。
  • 子句小工具和连接的直观想象
  • 假设子句 $c_j = (x_i \lor ...)$。这意味着如果 $x_i$ 为真,则 $c_j$ 被满足。
  • 在我们的图中,有一个代表 $c_j$ 的“宝藏”节点。
  • 我们在代表 $x_i$ 的那条走廊里,如果你选择了“从上向下”($x_i=$ 真)的路线,那么在某个特定的房间,会出现一条岔路,让你能够“顺便”去访问一下“宝藏”节点 $c_j$ 再回来,而不影响你继续走完走廊。
  • 但如果你选择了“从下向上”($x_i=$ 假)的路线,那么在那同一个房间,通往宝藏节点的岔路是“逆行”的,你无法使用它。
  • 因此,变量的赋值(走廊的遍历方向)决定了你是否能“解锁”通往特定宝藏节点的路径。
  • 由于哈密顿路径要求你必须拿到所有宝藏,你就必须为每个宝藏(子句)至少解锁一条通往它的路径,这等价于每个子句至少要被一个文字满足。
⚠️ [易错点]
  1. 小工具的隔离性变量小工具的设计必须保证路径只能“进入再出来”,不能从中间“跳”到别的变量小工具里去。菱形结构两端的“瓶颈”设计就是为了保证这一点。
  2. 绕行的代价:去访问子句节点的“绕行”必须是无缝的,即路径访问完子句节点后,必须能完美地回到它出发的地方,继续走完变量小工具,并且不能因此跳过变量小工具里的任何一个节点。
  3. 证明的复杂性:这个“证明思路”只是一个高度概括的蓝图。实际的证明需要非常精细地设计菱形内部的节点数量和连接方式,以防止出现意料之外的“捷径”或“死路”,破坏归约的逻辑。
📝 [总结]

本段清晰地勾勒出了 3SAT 到 HAMPATH 归约的证明蓝图。其核心思想是使用巧妙设计的“小工具”将逻辑世界中的概念映射到图论世界中:用具有两种遍历方式的“菱形结构”来模拟变量的真/假赋值,用单个“节点”来代表子句。通过精心设计的连接,使得哈密顿路径“必须访问所有子句节点”的图论约束,等价于“赋值必须满足所有子句”的逻辑约束。这个思路将一个静态的逻辑满足问题,转化为了一个动态的路径寻找问题。

🎯 [存在目的]

本段的目的是在读者陷入繁复的图构造细节之前,提供一个高层次的、直观的理解框架。它回答了最重要的问题:“这个复杂的图到底想干什么?”通过提前揭示菱形结构代表变量、单个节点代表子句以及“必须访问”等价于“必须满足”的核心思想,它让读者在后续阅读中能够有的放矢,理解每个构造细节背后的意图。

[直觉心-模型]

想象一个由多个“开关组”和多个“指示灯”组成的电路。

  1. 变量小工具:每个“开关组”(变量)是一个菱形的轨道,上面有一个小球。小球可以从左到右滚过,也可以从右到左滚过(二元选择),这代表了变量的赋值。
  2. 子句小工具:每个“指示灯”(子句)是一个需要被小球触碰一下才能点亮的装置。
  3. 连接:轨道上布满了精巧的触发器。例如,如果小球在“变量$x_i$”的轨道上“从左到右”滚动($x_i$=真),它就会在某个位置触发一个弹射杆,把另一个小球弹出去,正好能碰到“子句$c_j$”的指示灯。
  4. HAMPATH:一条哈密顿路径,就是小球的一条总运动轨迹,它必须穿过所有开关组,并且点亮所有指示灯。
  5. 等价性:是否存在这样一条轨迹,等价于是否存在一种设置所有开关的方式(赋值),使得所有指示灯都被点亮(所有子句都被满足)。
💭 [直观想象]

你是一个特技飞行员,要完成一项挑战。

  1. 场地:由 $l$ 个“菱形峡谷”(变量)和 $k$ 个“目标气球”(子句)组成。
  2. 规则
  1. 你必须从起点 $s$ 起飞,飞越每一个菱形峡谷,最后降落在终点 $t$
  2. 对于每个菱形峡谷,你只能选择两种固定航线中的一种飞过它(例如,“Z”字形或反“Z”字形)。
  3. 你必须在飞行过程中,撞破所有的目标气球。
    • 连接:不同的航线会让你在峡谷的不同位置,有机会做出一个短暂的“侧飞”,去撞破特定的气球,然后马上飞回主航线。选择“Z”字航线($x_i$=真)可能会让你有机会撞破A气球,而选择反“Z”字航线($x_i$=假)则没有这个机会。
    • HAMPATH 问题:是否存在一套航线选择方案(为每个峡谷选择一种飞法),使得你能够规划出一条连续的、不重复的飞行路径,飞越所有峡谷,并撞破所有气球?
    • 这个问题的答案,直接对应了原 3SAT 公式是否存在一个满足赋值。

由于篇幅限制,后续的详细解释将在下一个回复中继续。


4行间公式索引

  1. $$

\phi=\left(a_{1} \vee b_{1} \vee c_{1}\right) \wedge\left(a_{2} \vee b_{2} \vee c_{2}\right) \wedge \cdots \wedge\left(a_{k} \vee b_{k} \vee c_{k}\right),

$$ **解释**:这是一个标准的合取范式 (CNF) 公式,表示由 k 个子句通过“与”逻辑连接而成,每个子句是三个文字的“或”组合。 2. $$

\begin{aligned}

& S \rightarrow R T \\

& R \rightarrow T R \mid \mathrm{a} \\

& T \rightarrow T R \mid \mathrm{b}

\end{aligned}

$$ **解释**:这是一个上下文无关文法 (CFG) 的例子,用于练习题 7.4 中,定义了一套产生式规则。 3. $$

(x \vee y) \wedge(x \vee \bar{y}) \wedge(\bar{x} \vee y) \wedge(\bar{x} \vee \bar{y})

$$ **解释**:这是一个布尔可满足性问题的具体实例,用于练习题 7.5,询问该公式是否可满足。 4. $$

y_{1}, z_{1}, y_{2}, z_{2}, \ldots, y_{l}, z_{l} \quad \text { 和 } \quad g_{1}, h_{1}, g_{2}, h_{2}, \ldots, g_{k}, h_{k}

$$ **解释**:这是在 **SUBSET-SUM** 归约中,为变量和子句构造的数字集合 S 的一部分的符号表示。 ## 3.4. 详细证明 [原文] 证明 我们之前已证明 **HAMPATH** 属于 **NP**,因此剩下要做的就是证明 3**SAT** $\leq_{\mathrm{P}}$ **HAMPATH**。对于每个 3 **cnf**-公式 $\phi$,我们展示如何构造一个有向图 $G$,其中包含两个节点 $s$ 和 $t$,当且仅当 $\phi$ 是可满足的时,存在一条从 $s$ 到 $t$ 的哈密顿路径。 我们从包含 $k$ 个子句的 3 **cnf**-公式 $\phi$ 开始, $$

\phi=\left(a_{1} \vee b_{1} \vee c_{1}\right) \wedge\left(a_{2} \vee b_{2} \vee c_{2}\right) \wedge \cdots \wedge\left(a_{k} \vee b_{k} \vee c_{k}\right),

$$ 其中每个 $a, b$ 和 $c$ 是文字 $x_{i}$ 或 $\overline{x_{i}}$。令 $x_{1}, \ldots, x_{l}$ 为 $\phi$ 的 $l$ 个变量。 现在我们展示如何将 $\phi$ 转换为图 $G$。我们构造的图 $G$ 包含用于表示 $\phi$ 中出现的变量和子句的各个部分。 [逐步解释] 这部分正式开始进行 **3SAT 到 HAMPATH** 归约的构造性证明。 1. **“我们之前已证明 HAMPATH 属于 NP...”**: 再次确认 **NP-完全**性证明的第一步已经完成。 2. **“...剩下要做的就是证明 3SAT $\leq_{\mathrm{P}}$ HAMPATH。”**: 明确了当前证明的核心任务:构造一个从 **3SAT** 到 **HAMPATH** 的**多项式时间归约**。 3. **“对于每个 3 cnf-公式 $\phi$,我们展示如何构造一个有向图 $G$,其中包含两个节点 $s$ 和 $t$...”**: 这里描述了归约的输入和输出。 * **输入**: 任意一个 **3SAT** 公式的实例 $\phi$。 * **输出**: 一个**有向图** $G$ 和图中两个特定的节点,起点 $s$ 和终点 $t$。这个构造过程必须是**多项式时间**的,意味着如果 $\phi$ 的大小为 $n$,构造出图 $G$ 的时间复杂度必须是 $n$ 的某个多项式函数,如 $O(n^2)$。 4. **“...当且仅当 $\phi$ 是可满足的时,存在一条从 $s$ 到 $t$ 的哈密顿路径。”**: 这是对归约正确性的黄金标准要求。它必须建立一个完全等价的桥梁,连接逻辑世界和图论世界。 5. **“我们从包含 $k$ 个子句的 3 cnf-公式 $\phi$ 开始...”**: 设定了输入公式 $\phi$ 的一般形式。 * 它是一个合取范式 (Conjunctive Normal Form, CNF),由 $k$ 个子句通过“与”($\wedge$)连接。 * 每个子句是三个文字的“或”($\vee$)。 * 文字 (literal) 是指一个变量 $x_i$ 或它的否定 $\overline{x_i}$。 * $\phi$ 中总共有 $l$ 个不同的布尔变量 $x_1, \ldots, x_l$。 6. **“现在我们展示如何将 $\phi$ 转换为图 $G$。我们构造的图 $G$ 包含用于表示 $\phi$ 中出现的变量和子句的各个部分。”**: 预告了接下来的内容将是分步构造图 $G$。这个构造是模块化的,会分别处理变量和子句,也就是引入前面提到的“小工具”。 [公式与符号逐项拆解和推导(若本段含公式)] $$

\phi=\left(a_{1} \vee b_{1} \vee c_{1}\right) \wedge\left(a_{2} \vee b_{2} \vee c_{2}\right) \wedge \cdots \wedge\left(a_{k} \vee b_{k} \vee c_{k}\right),

$$ * $\phi$: 整个布尔公式。 * $\wedge$: 逻辑“与” (AND)。整个公式为真,当且仅当所有由 $\wedge$ 连接的部分都为真。 * $(a_j \vee b_j \vee c_j)$: 表示第 $j$ 个子句 (clause)。 * $\vee$: 逻辑“或” (OR)。一个子句为真,当且仅当其中至少有一个文字为真。 * $a_j, b_j, c_j$: 第 $j$ 个子句中的三个文字 (literal)。 * $x_i, \overline{x_i}$: 文字的具体形式。$x_i$ 是一个变量,$\overline{x_i}$ 是它的否定。例如,如果 $x_1$ 为真,则 $\overline{x_1}$ 为假。 * $l$: 公式中独立变量的总数。 * $k$: 公式中子句的总数。 [具体数值示例] * **输入公式 $\phi$**: $\phi = (x_1 \lor \overline{x_2} \lor x_3) \wedge (\overline{x_1} \lor x_2 \lor \overline{x_3})$ * **参数**: * 变量数 $l = 3$ (变量是 $x_1, x_2, x_3$) * 子句数 $k = 2$ (子句是 $c_1, c_2$) * **输出 (目标)**: 一个有向图 $G$ 和起终点 $s,t$。我们要构造这个 $G$,使得: * 如果 $\phi$ 有满足赋值 (例如 $x_1=$真, $x_2=$真, $x_3=$假,可以满足 $\phi$),那么 $G$ 中一定有一条 $s-t$ 哈密顿路径。 * 反之,如果在 $G$ 中找到一条 $s-t$ 哈密顿路径,我们一定能据此构造出 $\phi$ 的一个满足赋值。 [易错点与边界情况] * **有向图**: 必须时刻记住我们构造的是**有向图**,边的方向至关重要,它将用来强制路径的流动方向。 * **多项式时间**: 整个构造过程的效率是关键。后面会看到,图的大小(节点数和边数)是关于 $l$ 和 $k$ 的多项式函数,因此可以在多项式时间内完成构造。 [总结] 本段为 **HAMPATH** 的 **NP-完全**性证明设置了舞台。它重申了证明策略(通过从 **3SAT** 进行多项式时间归约来证明 **NP-难**度),并精确定义了归约的输入(一个任意的 3-CNF 公式 $\phi$)和输出(一个有向图 $G$)。最终目标是建立 $\phi$ 的可满足性与 $G$ 中 $s-t$ 哈密顿路径的存在性之间的严格等价关系。 [存在目的] 本段的目的是为复杂的构造过程提供一个清晰的引言和框架。它明确了我们将要做什么(将公式转换为图)以及为什么这么做(为了证明 **HAMPATH** 是 **NP-完全**的)。这使得读者在接触到具体的、看似随意的图构造细节时,能够理解这些细节都是为了服务于“模拟布尔逻辑”这一最终目的。 [直觉心智模型] 想象你是一个翻译,要把一本用“逻辑语言”写的小说(**3SAT** 公式)翻译成用“地图和路线语言”写的冒险指南(**HAMPATH** 问题)。 * 本段就是你的翻译项目简介。 * **项目目标**: 翻译必须是“保真”的,即小说有一个美好的结局(公式可满足),当且仅当冒险指南里存在一条能走通所有地点的完美路线(哈密顿路径)。 * **原料**: 小说由章节(子句)构成,章节里的人物有不同的选择(变量赋值)。 * **成品**: 一张包含起点、终点和许多中间地点的有向地图。 * 接下来的内容就是你的翻译手册,教你如何把小说中的每个元素(变量、子句)翻译成地图上的特定结构(小工具)。 [直观想象] 你是一位建筑师,接到一个奇特的设计任务。 * **客户要求**: 设计一个迷宫(有向图 $G$),有唯一的入口($s$)和出口($t$)。 * **设计约束**: 这个迷宫的设计图纸必须与一个给定的逻辑谜题(**3SAT** 公式 $\phi$)相关联。 * **核心要求**: 逻辑谜题有解(可满足),当且仅当有人能找到一条穿过迷宫的路线,这条路线必须不重不漏地访问迷宫中的每一个房间(哈密顿路径)。 * 本段就是这个设计任务的说明书。接下来的内容将告诉你如何根据逻辑谜题的结构,来设计迷宫中的“菱形大厅”(变量)和“关键房间”(子句)。 ### 3.4.1. 变量小工具构造 [原文] 我们用一个包含一行水平节点的菱形结构来表示每个变量 $x_{i}$,如下图所示。稍后我们将指定水平行中出现的节点数量。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-40.jpg?height=409&width=872&top_left_y=1864&top_left_x=479) 图 7.47 将变量 $x_{i}$ 表示为菱形结构 [逐步解释] 这部分开始具体介绍第一个**小工具**——用于模拟变量的**菱形结构**。 1. **“我们用一个...菱形结构来表示每个变量 $x_{i}$”**: * 对于公式中的每一个变量 $x_i, x_2, \ldots, x_l$,我们都在图中构建一个独立的、对应的**变量小工具**。 * 这个小工具的整体形状像一个菱形。它有顶部的入口节点和底部的出口节点,中间是一系列节点。 2. **“包含一行水平节点”**: * 菱形的核心是一串水平排列的节点。图 7.47 中,这些是中间那条长长的、由双向箭头连接的节点链。 * **双向箭头**意味着路径可以在这条链上向左走,也可以向右走。 3. **“如下图所示”**: * 图 7.47 展示了这个结构。它有两个主要部分: * **外壳**: 顶部的节点(我们称之为 $u_{i,top}$)和底部的节点($u_{i,bottom}$),以及连接它们和水平链两端的边。 * **核心**: 中间的水平节点链。 * 路径从 $u_{i,top}$ 进入,必须经过中间的水平链,最终从 $u_{i,bottom}$ 离开(或者反过来,如果全局结构允许的话)。 * 关键在于,要穿过这条水平链并访问其中的所有节点,只有两种基本方式: * **从左到右遍历**: 路径从左端的节点进入水平链,一路向右访问所有节点,从右端节点离开。 * **从右到左遍历**: 路径从右端的节点进入水平链,一路向左访问所有节点,从左端节点离开。 * 这两种唯一的、覆盖所有内部节点的遍历方式,将完美地对应变量 $x_i$ 的两种赋值:真和假。 4. **“稍后我们将指定水平行中出现的节点数量。”**: * 这是一个重要的伏笔。中间这条水平链到底需要多少个节点?这个数量不是随意的,它必须足够“长”,以容纳与所有子句相关的“岔路口”。 * 具体的节点数量取决于公式中**子句的数量 $k$**。这将在后面详细说明。现在我们只需要理解这个菱形结构的核心功能:强制路径二选一。 [具体数值示例] * 假设我们有一个变量 $x_1$。我们为它构建一个菱形小工具。 * **入口/出口**: 节点 $u_{1,top}, u_{1,bottom}$。 * **水平链**: 假设目前我们只需要 3 个水平节点 $h_{1,1}, h_{1,2}, h_{1,3}$。 * **连接**: * 有向边 $u_{1,top} \to h_{1,1}$ 和 $u_{1,top} \to h_{1,3}$。 * 水平链上的双向边 $h_{1,1} \leftrightarrow h_{1,2} \leftrightarrow h_{1,3}$。 * 有向边 $h_{1,1} \to u_{1,bottom}$ 和 $h_{1,3} \to u_{1,bottom}$。 * **路径选择**: 一条从 $u_{1,top}$ 进入并要访问所有水平节点再到 $u_{1,bottom}$ 的路径,必须是以下两种之一: 1. **真赋值路径 (例如,从左到右)**: $u_{1,top} \to h_{1,1} \to h_{1,2} \to h_{1,3} \to u_{1,bottom}$。 2. **假赋值路径 (例如,从右到左)**: $u_{1,top} \to h_{1,3} \to h_{1,2} \to h_{1,1} \to u_{1,bottom}$。 * 任何其他走法,比如 $u_{1,top} \to h_{1,1} \to u_{1,bottom}$,都会漏掉 $h_{1,2}$ 和 $h_{1,3}$,因此不可能是哈密顿路径的一部分。这个结构成功地强制了二选一。 [易错点与边界情况] * **边的方向**: 必须注意图中箭头的方向。例如,从顶部节点只能进入水平链,不能返回。从水平链只能走向底部节点,不能返回。这保证了路径的单向流动性。 * **“菱形”是比喻**: 这个结构在拓扑上像菱形,但重要的是它的连接属性和它如何限制路径的流动,而不是它的几何形状。 [总结] 本段介绍了 **3SAT 到 HAMPATH** 归约中的**变量小工具**。每个变量都被一个“菱形结构”所代表。这个结构的核心是一条水平的节点链,其设计巧妙地迫使任何希望包含其中所有节点的路径,都必须以两种固定方式之一(例如,从左到右或从右到左)来遍历它。这两种遍历方式将被用来完美地模拟相应变量的“真/假”二元赋值。 [存在目的] 本段的目的是引入归约构造的第一个基本构件。它展示了如何将逻辑世界中抽象的“二元选择”(变量赋值)转化为图论世界中具象的“路径选择”。这是整个复杂归约的第一块基石,为后续引入子句并建立逻辑约束奠定了基础。 [直觉心智模型] 想象一条单行道的两端有两个环岛。中间是双向车道。 * **菱形结构**:就是这两个环岛(顶部/底部节点)加上中间的双向车道(水平链)。 * **哈密顿路径**: 你必须开车从一个环岛到另一个环岛,并且必须经过双向车道上的每一个出口。 * **二选一**: 要做到这一点,你只能完整地从头到尾开一遍双向车道。你要么选择从A环岛进入,开到B环岛;要么从B环岛进入,开到A环岛。没有第三种方法能让你不漏掉任何一个出口。 * **赋值**: 这两种开车方向就代表了变量的两种赋值。 [直观想象] 你正在设计一个“二选一”的开关。 * **菱形结构**: 就是你设计的这个开关的内部机械结构。 * **路径**: 一根滑杆必须从开关的一头滑到另一头。 * **内部节点**: 滑杆上有一排必须被拨动的小齿轮。 * **二选一的遍历**: 要拨动所有小齿轮,滑杆必须选择两条预设的轨道之一来滑动。一条轨道对应“开”状态,另一条对应“关”状态。 * 这个机械开关(变量小工具)将被集成到一个更大的机器(整个图)中。 ### 3.4.2. 子句小工具构造 [原文] 我们用一个节点来表示 $\phi$ 的每个子句,如下所示。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-41.jpg?height=73&width=180&top_left_y=569&top_left_x=823) 图 7.48 将子句 $c_{j}$ 表示为节点 [逐步解释] 这部分描述了第二个**小工具**——用于表示子句的结构。 1. **“我们用一个节点来表示 $\phi$ 的每个子句”**: * 与变量小工具的复杂结构形成鲜明对比,子句小工具的设计在这里异常简单。 * 对于公式中的每一个子句 $c_1, c_2, \ldots, c_k$,我们就在图中创建一个对应的、单独的节点。 * 图 7.48 中,节点 $c_j$ 就代表了第 $j$ 个子句。 2. **小工具的目的**: * 这个节点本身没有任何特殊的内部结构。它的作用完全体现在它将如何与变量小工具连接,以及哈密顿路径对它的要求。 * **哈密顿路径必须访问图中每一个节点**。这意味着,我们最终构造的路径,必须想办法“绕道”去访问每一个这样的子句节点 $c_j$。 * 这个“必须访问”的约束,将被我们用来模拟“子句必须被满足”的逻辑要求。 [具体数值示例] * **公式 $\phi$**: $\phi = (x_1 \lor \overline{x_2}) \wedge (\overline{x_1} \lor x_2)$ * **子句**: $c_1 = (x_1 \lor \overline{x_2})$ 和 $c_2 = (\overline{x_1} \lor x_2)$。 * **子句小工具**: * 我们在图中创建两个节点,一个叫 $C_1$,另一个叫 $C_2$。 * 在哈密顿路径的规划中,我们必须确保路径会经过 $C_1$,也会经过 $C_2$。 [易错点与边界情况] * **不要低估其简单性**: 初学者可能会觉得这个小工具太简单了,是不是有什么隐藏的复杂性。其实没有。它的力量完全来自于它与变量小工具的外部连接,以及哈密顿路径的全局约束。简单,但有效。 * **与 VERTEX-COVER 的对比**: 回想一下,在 **3SAT 到 VERTEX-COVER** 的归约中,子句小工具是一个三角形,有复杂的内部结构。这里的子句小工具只是一个点。这再次提醒我们,不同的归约问题需要完全不同的、量身定做的**小工具**。 [总结] 本段介绍了 **3SAT 到 HAMPATH** 归约中极其简洁的**子句小工具**:每个子句由图中的一个单节点来代表。它的核心作用是成为哈密顿路径必须访问的一个“打卡点”。这个“必须打卡”的图论要求,将通过巧妙的连接,被转化为“子句必须被满足”的逻辑要求。 [存在目的] 本段引入了归约的第二个基本构件。通过呈现一个设计上极其简单的**子句小工具**,它与复杂的**变量小工具**形成对比,并引导读者思考:这两个功能和形态迥异的小工具将如何协同工作,以实现对布尔逻辑的精确模拟?这为下一阶段介绍全局结构和连接方式做好了铺垫。 [直觉心智模型] 回到电路模型: * **子句小工具**:就是一个指示灯。它本身很简单,就是一个灯泡。 * **哈密顿路径要求**: 最终的电路必须能点亮(访问)所有的指示灯。 * 这个灯泡能否被点亮,不取决于它自己,而取决于连接到它的电线(与变量小工具的连接)以及开关的状态(变量赋值)。 [直观想象] 回到特技飞行挑战: * **子句小工具**:就是一个必须撞破的目标气球。它只是一个静静地飘在那里的气球。 * **哈密顿路径要求**: 你的飞行路线必须规划得能撞破所有这些气球。 * 你能否撞到这个气球,取决于你是否能从某个菱形峡谷中找到一条通往它的“侧飞”航线。气球本身是无辜的,关键在于通往它的路。 ### 3.4.3. 图的全局结构 [原文] 下图描绘了 $G$ 的全局结构。它显示了 $G$ 的所有元素及其关系,除了表示变量与包含它们的子句之间关系的边。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-41.jpg?height=1136&width=856&top_left_y=1100&top_left_x=487) 图 7.49 $G$ 的高层结构 [逐步解释] 这部分展示了如何将之前介绍的**变量小工具**和**子句小工具**组装成一个完整的图的“骨架”。 1. **“下图描绘了 $G$ 的全局结构”**: * 图 7.49 不是最终的图,而是高层次的蓝图。它展示了各个主要部件是如何串联起来的。 2. **起点 $s$ 和终点 $t$**: * 图的顶部有一个全局的起点 $s$,底部有一个全局的终点 $t$。哈密顿路径必须从 $s$ 开始,到 $t$ 结束。 3. **变量小工具的串联**: * 所有的**变量小工具**(菱形结构)被像串珠子一样一个接一个地串联起来。 * 路径从起点 $s$ 出发,首先进入第一个变量小工具(代表 $x_1$)。 * 从第一个变量小工具的底部出来后,进入第二个变量小工具(代表 $x_2$)的顶部。 * 这个过程一直持续,直到路径从最后一个变量小工具(代表 $x_l$)的底部出来。 * 最后,从最后一个变量小工具的底部,有一条边指向全局终点 $t$。 * 这种串联结构强制哈密顿路径必须按顺序依次穿过每一个变量小工具。它不能跳过任何一个菱形,也不能打乱顺序。 4. **子句小工具的位置**: * 所有的**子句小工具**(单个节点 $c_1, \ldots, c_k$)被放置在一边,目前看起来是孤立的。它们还没有与主路径连接起来。 5. **缺失的边**: * **“除了表示变量与包含它们的子句之间关系的边”**: 这是本图的关键说明。这张图故意省略了最重要的连接——那些能让路径从**变量小工具**“绕道”去访问**子句小工具**的边。 * 这些缺失的边才是整个归约的灵魂,它们将根据公式 $\phi$ 的具体内容(即哪个子句包含哪个文字)来添加。 [具体数值示例] * **公式**: $\phi$ 有两个变量 $x_1, x_2$ 和三个子句 $c_1, c_2, c_3$。 * **全局结构**: * 一个起点 $s$ 和一个终点 $t$。 * $s$ 连接到 $x_1$ 菱形的顶部。 * $x_1$ 菱形的底部连接到 $x_2$ 菱形的顶部。 * $x_2$ 菱形的底部连接到 $t$。 * 主路径的骨架是: $s \to \text{菱形}_1 \to \text{菱形}_2 \to t$。 * 旁边放着三个孤立的节点: $C_1, C_2, C_3$。 * 下一步的工作就是设计从 $\text{菱形}_1$ 和 $\text{菱形}_2$ 内部的特定位置,引出边来连接 $C_1, C_2, C_3$。 [易错点与边界情况] * **这只是骨架**: 必须清楚这还不是完整的图。如果只看这张图,哈密顿路径是 $s \to ... \to t$,它根本没有访问任何子句节点,所以它不可能是哈密tonian的。这张图只是为了展示主要组件的排列方式。 * **路径的强制流向**: 串联结构和边的方向性共同确保了路径的主干流是固定的、不可更改的,为后续的“绕行”提供了稳定的基础。 [总结] 本段通过图 7.49 展示了所构造的图 $G$ 的高层骨架。它由一个全局的起点 $s$ 和终点 $t$、一串依次串联的变量小工具(菱形结构)、以及一组目前孤立的子句小工具(单个节点)组成。这种布局强制任何从 $s$ 到 $t$ 的哈密顿路径都必须按顺序穿越每一个变量小工具。图中尚未画出的是连接变量和子句小工具的关键边,这些边将赋予图完整的逻辑功能。 [存在目的] 本段的目的是从宏观上展示图的组织结构,让读者对路径的基本流向有一个整体的认识。通过先呈现一个清晰、有序的“骨架”,再在后续步骤中添加复杂的“血肉”(连接边),可以使整个构造过程更有层次感,更易于理解。这是一种“由粗到精”的教学方法。 [直觉心-模型] 想象你在设计一个闯关游戏。 * **全局结构**: 游戏的主线是一条笔直的大道,从起点通往终点。 * **变量小工具**: 大道被分成了 $l$ 个赛段(菱形),你必须按顺序通过每一个赛段。 * **子句小工具**: 在大道两旁,有 $k$ 个必须拾取的宝藏(子句节点)。 * **当前状态**: 你已经铺好了主干道和各个赛段,也把宝藏放在了路边。但你还没有修建任何从主干道通往宝藏的岔路。现在的地图上,你只能沿着主干道走,拿不到任何宝藏。 [直观想象] 你正在组装一根复杂的“魔法棒”。 * **全局结构**: 魔法棒的主体由 $l$ 节“能量核心”(变量小工具)依次串联而成,两端是握柄($s$)和顶端宝石($t$)。 * **子句小工具**: 棒身旁边还预留了 $k$ 个插槽,需要镶嵌“符文石”(子句节点)。 * **当前状态**: 你已经把主体的能量核心都串好了,符文石也放在了旁边。但还没有连接任何导线,将能量核心的能量引导至符文石插槽。现在的魔法棒,能量只能从头传到尾,无法激活任何符文石。 ### 3.4.4. 菱形结构内部细节 [原文] 接下来,我们展示如何将表示变量的菱形连接到表示子句的节点。每个菱形结构都包含一行水平节点,这些节点由双向边连接。水平行除了菱形两端的两个节点外,还包含 $3k+1$ 个节点。这些节点被分组为相邻对,每个子句一对,并在每对旁边附加分隔节点,如下图所示。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-42.jpg?height=191&width=888&top_left_y=795&top_left_x=471) 图 7.50 菱形结构中的水平节点 [逐步解释] 这部分揭示了之前被“藏起来”的菱形结构内部的精确设计,这是整个归约最精巧的部分之一。 1. **“每个菱形结构都包含一行水平节点...”**: 重申了菱形的核心是水平链。 2. **“水平行除了菱形两端的两个节点外,还包含 $3k+1$ 个节点。”**: 这里终于给出了水平链的精确长度。 * $k$ 是公式中子句的数量。 * 这条链的长度与子句数量 $k$ 相关,这暗示了它的设计目的就是为了与所有 $k$ 个子句产生联系。 * 为什么是 $3k+1$?这个数字不是随意的。 3. **“这些节点被分组为相邻对,每个子句一对...”**: * 在这一长串水平节点中,我们为**每一个**子句 $c_1, c_2, \ldots, c_k$ 都预留了一对相邻的节点。 * 例如,图 7.50 中,标有“for $c_1$”的那两个节点,就是为子句 $c_1$ 准备的“岔路口”。标有“for $c_j$”的两个节点是为子句 $c_j$ 准备的,以此类推。 * 总共有 $k$ 个子句,所以需要 $k$ 对节点,即 $2k$ 个节点。 4. **“...并在每对旁边附加分隔节点...”**: * 在每两对“子句节点对”之间,以及在链的两端,都插入了一个“分隔节点 (separator node)”。 * 看图 7.50,左右两端各有一个分隔节点,每两个“for $c_j$”的节点对之间也有一个分隔节点。 * 如果有 $k$ 个节点对,那么它们之间就有 $k-1$ 个空隙,需要 $k-1$ 个分隔节点。再加上两端各一个,总共需要 $(k-1)+2 = k+1$ 个分隔节点。 * **总节点数验证**: $k$ 个节点对($2k$ 个节点) + $(k+1)$ 个分隔节点 = $3k+1$ 个节点。这与前面给出的数字完全吻合。 5. **分隔节点的目的**: * 分隔节点的作用是**隔离**。它们确保从一个“子句节点对”出发的绕行,必须回到这个节点对本身,而不能“跳”到相邻的另一个节点对去。它们像防火墙一样,保证了每个子句的逻辑是独立处理的。这是防止出现意外“短路”的关键设计。 [具体数值示例] * **公式**: $\phi$ 有 $l=2$ 个变量 ($x_1, x_2$) 和 $k=3$ 个子句 ($c_1, c_2, c_3$)。 * **考虑变量 $x_1$ 的菱形小工具**: * 它的水平链需要有 $3k+1 = 3*3+1 = 10$ 个中间节点。 * **结构**: * 分隔节点1 * 为 $c_1$ 准备的节点对 (2个) * 分隔节点2 * 为 $c_2$ 准备的节点对 (2个) * 分隔节点3 * 为 $c_3$ 准备的节点对 (2个) * 分隔节点4 * 总节点数: $1+2+1+2+1+2+1 = 10$。 * 这 10 个节点和菱形两端的出入节点,共同构成了 $x_1$ 的变量小工具。变量 $x_2$ 的小工具也具有完全相同的内部结构。 [易错点与边界情况] * **每个变量都有完整的结构**: 必须理解,是**每一个**菱形小工具内部都包含了为**所有** $k$ 个子句准备的节点对。变量 $x_1$ 的菱形里有为 $c_1, c_2, ..., c_k$ 准备的岔路口;变量 $x_2$ 的菱形里也有一套完整的、为 $c_1, c_2, ..., c_k$ 准备的岔路口。 * **分隔节点的重要性**: 如果没有分隔节点,那么当路径从 $c_j$ 的节点对绕行出去后,可能会错误地返回到 $c_{j+1}$ 的节点对中,这将导致逻辑混乱,归约失败。 [总结] 本段详细揭示了**变量小工具**中水平节点链的精密内部结构。这条链的长度被确定为 $3k+1$(其中 $k$ 是子句总数),并被划分为 $k$ 个“子句节点对”和 $k+1$ 个“分隔节点”。每个节点对都将作为与特定子句进行交互的“接口”或“岔路口”,而分隔节点则起到了关键的隔离作用,确保不同子句的逻辑不会互相干扰。这个设计为将变量的路径选择与所有子句的满足状态联系起来做好了准备。 [存在目的] 本段的目的是深入到**小工具**设计的核心,展示其复杂性和精巧性。它回答了“菱形中间那条线到底是什么”的问题。通过揭示这个由节点对和分隔符组成的重复结构,它为下一步连接变量和子句的操作提供了具体的“锚点”,让读者明白连接将发生在这些预留好的“接口”上。 [直觉心-模型] 回到闯关游戏的主干道赛段(菱形)。 * **水平链的结构**: 每个赛段(变量)的道路不是平坦的,而是由一系列“特殊区域”组成的。 * **子句节点对**: 对应子句 $c_j$ 的“特殊区域”,是一个包含两个并排停车位的“服务区”。这是唯一可以临时离开主路的地方。 * **分隔节点**: 每两个服务区之间都有一个“收费站”。你必须通过收费站才能到下一个服务区。这个收费站确保你从一个服务区离开后,不能直接开到另一个服务区的停车场里,只能回到主路上。 * 这个设计意味着,如果你想从赛段 $x_i$ 的主路去拿宝藏 $c_j$,你必须在为 $c_j$ 预留的那个服务区驶离主路。 [直观想象] 回到魔法棒的能量核心(菱形)。 * **水平链的结构**: 能量核心的内部是一串水晶。 * **子句节点对**: 其中某些成对的水晶是“接口水晶”,它们是为特定的符文石(子句)准备的能量输出端口。 * **分隔节点**: 在每对“接口水晶”之间,都有一种“绝缘水晶”,防止能量从一个端口泄漏到另一个端口。 * 当能量(路径)流过这串水晶时,它可以在“接口水晶”的位置被引导出去,为对应的符文石充能。绝缘水晶保证了能量流的精确控制。 ### 3.4.5. 连接小工具:正文字 [原文] 如果变量 $x_{i}$ 出现在子句 $c_{j}$ 中,我们从第 $i$ 个菱形中的第 $j$ 对向第 $j$ 个子句节点添加以下两条边。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-42.jpg?height=380&width=940&top_left_y=1442&top_left_x=436) 图 7.51 当子句 $c_{j}$ 包含 $x_{i}$ 时附加的边 [逐步解释] 这部分和下一部分是归约的“点睛之笔”,它们最终将**变量小工具**和**子句小工具**连接起来,从而注入布尔逻辑。 1. **“如果变量 $x_{i}$ 出现在子句 $c_{j}$ 中...”**: * 这是添加边的**条件**。我们现在开始根据公式 $\phi$ 的具体内容来画边。 * 我们检查每一个子句 $c_j$ 中的每一个文字。这个规则处理的是**正文字**(没有“非”的变量,如 $x_i$)。 2. **“...我们从第 $i$ 个菱形中的第 $j$ 对...”**: * **第 $i$ 个菱形**: 指的是代表变量 $x_i$ 的那个**变量小工具**。 * **第 $j$ 对**: 指的是在该菱形的水平链上,我们为子句 $c_j$ 预留的那一对相邻的节点。 3. **“...向第 $j$ 个子句节点添加以下两条边。”**: * **第 $j$ 个子句节点**: 指的是代表子句 $c_j$ 的那个单节点(我们称之为 $C_j$)。 * 我们添加的不是一条边,而是**两条有向边**,形成一个“绕行”的回路。 4. **图 7.51 的解释**: * 图中展示了变量 $x_i$ 菱形中为子句 $c_j$ 准备的节点对,我们称它们为 $u_{i,j,left}$ 和 $u_{i,j,right}$。 * 添加的边是: * 一条从 $u_{i,j,left}$ 指向子句节点 $C_j$ 的有向边。 * 一条从子句节点 $C_j$ 指向 $u_{i,j,right}$ 的有向边。 * 这两条边形成了一个路径片段: $... \to u_{i,j,left} \to C_j \to u_{i,j,right} \to ...$ 5. **这个连接的逻辑含义**: * 这两条边的方向是关键。它们允许路径在从左到右经过这对节点时,顺畅地“绕道”访问 $C_j$。 * 回忆一下,我们将变量小工具的“从左到右”遍历与变量赋值为“真”相关联。 * 因此,这个连接结构意味着:**如果 $x_i$ 被赋值为真(路径从左到右走),那么在经过为子句 $c_j$ 预留的岔路口时,路径就有机会去访问 $c_j$ 对应的子句节点。** * 如果路径是“从右到左”走的($x_i$ 赋值为假),那么在经过这对节点时,流向是 $... \to u_{i,j,right} \to u_{i,j,left} \to ...$。此时,边 $u_{i,j,left} \to C_j$ 是顺行的,但 $C_j \to u_{i,j,right}$ 是逆行的。路径无法从 $C_j$ 返回到主路上,所以这条绕行路径是**不可用**的。 [具体数值示例] * **公式**: $\phi$ 包含子句 $c_2 = (x_1 \lor x_3 \lor \overline{x_4})$。 * **我们关注文字 $x_1$ 和子句 $c_2$**: * 因为 $c_2$ 包含正文字 $x_1$。 * **操作**: * 找到代表变量 $x_1$ 的第 1 个菱形。 * 在这个菱形的水平链上,找到为子句 $c_2$ 预留的第 2 对节点。我们称之为 $(u_{1,2,L}, u_{1,2,R})$。 * 找到代表子句 $c_2$ 的单节点 $C_2$。 * 添加两条有向边:$u_{1,2,L} \to C_2$ 和 $C_2 \to u_{1,2,R}$。 * **结果**: * 如果我们将 $x_1$ 赋值为真,那么哈密顿路径将从左到右穿过 $x_1$ 的菱形。当它走到 $u_{1,2,L}$ 时,它可以选择岔路 $u_{1,2,L} \to C_2 \to u_{1,2,R}$,这样就成功访问了 $C_2$,然后再继续向右走。 * 如果我们将 $x_1$ 赋值为假,路径从右到左走。当它走到 $u_{1,2,R}$ 时,它无法使用这条岔路,因为它无法从 $C_2$ 回到 $u_{1,2,R}$(箭头方向反了)。 [易错点与边界情况] * **边的方向至关重要**: 哪怕只有一条边的方向画反,整个归约的逻辑就会崩溃。这个“左进右出”的设计是专门为“从左到右”的路径服务的。 * **一一对应**: 必须为公式中每一个正文字的每一次出现,都添加这样一对边。如果一个变量 $x_i$ 出现在多个子句中,那么在 $x_i$ 的菱形里,将会有多个节点对引出边,分别连向不同的子句节点。 [总结] 本段描述了如何为公式中的**正文字**添加连接边。当子句 $c_j$ 包含变量 $x_i$ 时,就在 $x_i$ 的变量小工具中为 $c_j$ 预留的节点对上,构建一个“左进右出”的、通向子句节点 $C_j$ 的有向回路。这个结构的功能是:只有当 $x_i$ 被赋值为“真”(对应于路径从左到右遍历)时,哈密顿路径才能利用这个回路去“访问”子句节点 $C_j$。这成功地将逻辑“或”的一部分——“如果 $x_i$ 为真,则 $c_j$ 满足”——翻译成了图论中的路径可能性。 [存在目的] 本段的目的是开始填充图的“血肉”,注入具体的逻辑关系。它是将之前孤立的变量和子句小工具联系起来的第一步。通过展示这个非对称的、依赖于路径方向的连接方式,它揭示了整个归约机制的核心:利用有向边来模拟逻辑蕴含。 [直觉心智模型] 回到闯关游戏: * **条件**: 宝藏 $c_j$ 的说明书上写着:“需要 $x_i$ 的‘真能量’才能获取”。 * **操作**: 在赛段 $x_i$ 的主干道上,为 $c_j$ 预留的服务区,你修建了一条单行道的岔路。这条岔路从服务区的入口(左边停车位)出发,绕到宝藏 $c_j$ 的位置,再从服务区的出口(右边停车位)汇入主路。 * **效果**: 只有当你选择“从左到右”通过这个赛段时($x_i$ 为真),你才能顺畅地开上这条岔路,拿到宝藏,再开回主路。如果你是“从右到左”开的,这条岔路就是逆行,你上不去。 [直观想象] 回到魔法棒: * **条件**: 符文石 $c_j$ 需要由能量核心 $x_i$ 在“正向转动”($x_i$=真)时产生的能量来激活。 * **操作**: 在能量核心 $x_i$ 内部,为符文石 $c_j$ 预留的“接口水晶”对上,你连接了两根特殊的单向“能量导管”。一根从左边水晶导出能量到符文石,另一根从符文石导回能量到右边水晶。 * **效果**: 只有当能量是“从左到右”流过核心时($x_i$=真),能量才能顺着导管流出去,激活符文石,再流回来。如果能量是反向流动的,导管的单向阀会阻止能量的激活回路。 ### 3.4.6. 连接小工具:负文字 [原文] 如果 $\overline{x_{i}}$ 出现在子句 $c_{j}$ 中,我们从第 $i$ 个菱形中的第 $j$ 对向第 $j$ 个子句节点添加两条边,如图 7.52 所示。 在我们添加完与每个 $x_{i}$ 或 $\overline{x_{i}}$ 在每个子句中出现的对应边后,$G$ 的构造就完成了。为了证明这个构造是有效的,我们论证如果 $\phi$ 是可满足的,则存在从 $s$ 到 $t$ 的哈密顿路径;反之,如果存在这样的路径,则 $\phi$ 是可满足的。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-43.jpg?height=374&width=934&top_left_y=426&top_left_x=446) 图 7.52 当子句 $c_{j}$ 包含 $\overline{x_{i}}$ 时附加的边 [逐步解释] 这部分与上一部分对称,处理的是**负文字**(带“非”的变量,如 $\overline{x_i}$)的情况。 1. **“如果 $\overline{x_{i}}$ 出现在子句 $c_{j}$ 中...”**: * 这是添加边的另一个**条件**,针对负文字。 2. **“...我们从第 $i$ 个菱形中的第 $j$ 对向第 $j$ 个子句节点添加两条边,如图 7.52 所示。”**: * 与正文字情况类似,我们同样在变量 $x_i$ 的菱形中,找到为子句 $c_j$ 预留的那对节点。 * 但是,这次添加的边的方向**正好相反**。 3. **图 7.52 的解释**: * 我们仍然使用节点对 $u_{i,j,left}$ 和 $u_{i,j,right}$。 * 添加的边是: * 一条从 $u_{i,j,right}$ 指向子句节点 $C_j$ 的有向边。 * 一条从子句节点 $C_j$ 指向 $u_{i,j,left}$ 的有向边。 * 这两条边形成了一个路径片段: $... \to u_{i,j,right} \to C_j \to u_{i,j,left} \to ...$ 4. **这个连接的逻辑含义**: * 这个“右进左出”的结构,是专门为“从右到左”的路径服务的。 * 我们将变量小工具的“从右到左”遍历与变量赋值为“假”相关联。 * 因此,这个连接结构意味着:**如果 $x_i$ 被赋值为假(即 $\overline{x_i}$ 为真,路径从右到左走),那么在经过为子句 $c_j$ 预留的岔路口时,路径就有机会去访问 $c_j$ 对应的子句节点。** * 如果路径是“从左到右”走的($x_i$ 赋值为真),那么在经过这对节点时,流向是 $... \to u_{i,j,left} \to u_{i,j,right} \to ...$。此时,通往 $C_j$ 的岔路是逆行的,**不可用**。 5. **“在我们添加完...对应边后,$G$ 的构造就完成了。”**: * 这是一个重要的阶段性总结。我们已经描述了图中所有的节点和边:起点/终点,串联的变量小工具(内部有精细结构),孤立的子句节点,以及根据公式内容添加的、连接变量和子句的“逻辑边”。至此,从公式 $\phi$ 到图 $G$ 的转换算法已经完整描述完毕。 6. **“为了证明这个构造是有效的...”**: * 预告了接下来的内容将是证明这个构造确实建立了“可满足性”与“哈密顿路径”之间的等价关系。这将是整个定理证明的高潮部分。 [具体数值示例] * **公式**: $\phi$ 包含子句 $c_2 = (x_1 \lor x_3 \lor \overline{x_4})$。 * **我们关注文字 $\overline{x_4}$ 和子句 $c_2$**: * 因为 $c_2$ 包含负文字 $\overline{x_4}$。 * **操作**: * 找到代表变量 $x_4$ 的第 4 个菱形。 * 在这个菱形的水平链上,找到为子句 $c_2$ 预留的第 2 对节点。我们称之为 $(u_{4,2,L}, u_{4,2,R})$。 * 找到代表子句 $c_2$ 的单节点 $C_2$。 * 添加两条有向边:$u_{4,2,R} \to C_2$ 和 $C_2 \to u_{4,2,L}$。 * **结果**: * 如果我们将 $x_4$ 赋值为假 ($\overline{x_4}$ 为真),那么哈密顿路径将从右到左穿过 $x_4$ 的菱形。当它走到 $u_{4,2,R}$ 时,它可以选择岔路 $u_{4,2,R} \to C_2 \to u_{4,2,L}$,成功访问 $C_2$,然后再继续向左走。 * 如果我们将 $x_4$ 赋值为真,路径从左到右走。当它走到 $u_{4,2,L}$ 时,它无法使用这条岔路。 [易错点与边界情况] * **对称性**: 正文字和负文字的连接方式是中心对称的,一个服务于“左到右”路径,另一个服务于“右到左”路径。这种对称性是模拟布尔逻辑“真/假”的关键。 * **一个节点对,多种可能**: 在一个变量 $x_i$ 的菱形中,为子句 $c_j$ 预留的节点对 $(u_{i,j,L}, u_{i,j,R})$,最多只会引出一种岔路。如果 $c_j$ 中同时包含 $x_i$ 和 $\overline{x_i}$(虽然在 3SAT 中不常见,但理论上可能),那么这个归约可能会出问题。但标准的 3SAT 问题通常假设每个子句中的文字对应的变量是不同的。 [总结] 本段完整了连接边的构造,描述了如何为**负文字**添加边。当子句 $c_j$ 包含 $\overline{x_i}$ 时,就在 $x_i$ 菱形中为 $c_j$ 预留的节点对上,构建一个“右进左出”的、通向子句节点 $C_j$ 的有向回路。这个结构确保了只有当 $x_i$ 被赋值为“假”(对应路径从右到左遍历)时,才有机会访问 $C_j$。至此,从 3-CNF 公式 $\phi$ 到有向图 $G$ 的完整构造过程已经全部描述完毕,下一步将是对其正确性进行严格证明。 [存在目的] 本段的目的是完成图的构造,并建立与正文字情况完全对称的逻辑。它使得变量的两种赋值(两种遍历方向)都能有选择地、正确地影响子句的满足状态。在完成了所有部分的构造后,本段也起到了一个承上启下的作用,宣告物理构造阶段结束,逻辑证明阶段即将开始。 [直觉心智模型] 回到闯关游戏: * **条件**: 宝藏 $c_j$ 的说明书上写着:“需要 $x_i$ 的‘假能量’才能获取”。 * **操作**: 在赛段 $x_i$ 的主干道上,为 $c_j$ 预留的服务区,你修建了另一条单行道岔路。这条路从服务区的出口(右边停车位)出发,绕到宝藏,再从入口(左边停车位)汇入主路。 * **效果**: 只有当你选择“从右到左”通过这个赛段时($x_i$ 为假),你才能顺畅地使用这条岔路。如果你是“从左到右”开的,这条路就是逆行。 [直观想象] 回到魔法棒: * **条件**: 符文石 $c_j$ 需要由能量核心 $x_i$ 在“反向转动”($x_i$=假)时产生的能量来激活。 * **操作**: 在为 $c_j$ 预留的“接口水晶”对上,你连接了两根方向相反的“能量导管”:一根从右边水晶导出能量,另一根导回能量到左边水晶。 * **效果**: 只有当能量是“从右到左”流过核心时($x_i$=假),能量才能激活符文石。 * **构造完成**: 现在,魔法棒上所有的导线都已连接完毕。每个能量核心(变量)的转动方向(赋值),都决定了它能为哪些符文石(子句)提供能量。 ### 3.4.7. 正确性证明(一):可满足 $\Rightarrow$ 哈密顿路径 [原文] 假设 $\phi$ 是可满足的。为了演示一条从 $s$ 到 $t$ 的哈密顿路径,我们首先忽略子句节点。路径从 $s$ 开始,依次经过每个菱形,并最终到达 $t$。要经过菱形中的水平节点,路径要么从左到右之字形行进,要么从右到左之字形行进;$\phi$ 的满足赋值决定了哪种方式。如果 $x_{i}$ 被赋值为真,路径之字形穿过相应的菱形。如果 $x_{i}$ 被赋值为假,路径反之字形行进。我们将在下图中展示两种可能性。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-43.jpg?height=403&width=881&top_left_y=1329&top_left_x=477) 图 7.53 由满足赋值决定的菱形之字形和反之字形遍历 到目前为止,这条路径覆盖了 $G$ 中除了子句节点外的所有节点。我们可以通过在水平节点处增加绕行轻松地包含它们。在每个子句中,我们选择一个通过满足赋值被赋值为 TRUE 的文字。 如果我们在子句 $c_{j}$ 中选择了 $x_{i}$,我们可以在第 $i$ 个菱形中的第 $j$ 对处绕行。这样做是可能的,因为 $x_{i}$ 必须为 TRUE,所以路径以之字形从左到右穿过相应的菱形。因此,通往 $c_{j}$ 节点的边顺序正确,允许绕行并返回。 类似地,如果我们在子句 $c_{j}$ 中选择了 $\overline{x_{i}}$,我们可以在第 $i$ 个菱形中的第 $j$ 对处绕行,因为 $x_{i}$ 必须为 FALSE,所以路径以反之字形从右到左穿过相应的菱形。因此,通往 $c_{j}$ 节点的边同样顺序正确,允许绕行并返回。(请注意,子句中的每个真文字都提供了绕行以到达子句节点的一个选项。因此,如果一个子句中有多个文字为真,则只进行一次绕行。)因此,我们构造了所需的哈密顿路径。 [逐步解释] 这部分开始证明的第一个方向:如果 $\phi$ 可满足,那么我们一定能在图 $G$ 中构造出一条哈密顿路径。 1. **“假设 $\phi$ 是可满足的。”**: 这是证明的前提。我们已经有了一个确定的、能让所有子句都为真的赋值方案。 2. **“路径从 $s$ 开始,依次经过每个菱形,并最终到达 $t$。”**: 我们先规划路径的主干。根据全局结构,路径必须是 $s \to \text{菱形}_1 \to \text{菱形}_2 \to \cdots \to \text{菱形}_l \to t$。 3. **“$\phi$ 的满足赋值决定了哪种方式。”**: 这是关键的第一步。我们根据已知的满足赋值,来确定穿越每个菱形的方式。 * **如果 $x_i$ 为真**: 路径“从左到右”穿过第 $i$ 个菱形。原文用“之字形 (zig-zag)”来描述,如图 7.53 上半部分所示,路径在水平链的上下两层节点(原文之前的图示比较模糊,这里才揭示水平链其实有两层,或者说这里的“之字形”是指在节点对之间移动)之间交替前进。简单理解就是“左到右”遍历。 * **如果 $x_i$ 为假**: 路径“从右到左”穿过第 $i$ 个菱形。原文用“反之字形 (zag-zig)”描述,如图 7.53 下半部分所示。简单理解就是“右到左”遍历。 4. **“到目前为止,这条路径覆盖了 $G$ 中除了子句节点外的所有节点。”**: 我们沿着这个由赋值决定的主干路径走,已经访问了 $s, t$ 以及所有变量小工具内部的全部节点。唯一被遗漏的,就是那些代表子句的单节点。 5. **“我们可以通过在水平节点处增加绕行轻松地包含它们。”**: 下一步就是修改主干路径,加入对子句节点的访问。 6. **“在每个子句中,我们选择一个通过满足赋值被赋值为 TRUE 的文字。”**: * 因为 $\phi$ 是可满足的,所以每个子句 $c_j$ 都至少有一个真文字。我们随便选一个。 * 对于每个子句 $c_j$,我们指定一个“负责”满足它的真文字,记为 $L_j$。 7. **“如果我们在子句 $c_j$ 中选择了 $x_i$...”**: * 这意味着 $L_j = x_i$。根据赋值,$x_i$ 必须为真。 * 因此,路径在穿过第 $i$ 个菱形时,是“从左到右”走的。 * 当路径走到为 $c_j$ 预留的节点对 $(u_{i,j,L}, u_{i,j,R})$ 时,由于路径是“从左到右”,并且我们之前为正文字 $x_i$ 添加了 $u_{i,j,L} \to C_j \to u_{i,j,R}$ 的边,所以路径可以自然地扩展为:$... \to u_{i,j,L} \to C_j \to u_{i,j,R} \to ...$。 * 我们通过这个“绕行”,成功地将子句节点 $C_j$ 加入了路径。 8. **“类似地,如果我们在子句 $c_j$ 中选择了 $\overline{x_i}$...”**: * 这意味着 $L_j = \overline{x_i}$。根据赋值,$x_i$ 必须为假。 * 因此,路径在穿过第 $i$ 个菱形时,是“从右到左”走的。 * 当路径走到为 $c_j$ 预留的节点对 $(u_{i,j,L}, u_{i,j,R})$ 时,由于路径是“从右到左”,并且我们之前为负文字 $\overline{x_i}$ 添加了 $u_{i,j,R} \to C_j \to u_{i,j,L}$ 的边,所以路径可以自然地扩展为:$... \to u_{i,j,R} \to C_j \to u_{i,j,L} \to ...$。 * 我们同样通过这个“绕行”,成功地将子句节点 $C_j$ 加入了路径。 9. **“如果一个子句中有多个文字为真,则只进行一次绕行。”**: * 这是一个重要的澄清。一个子句可能被多个真文字满足,这意味着我们有多个“绕行”的机会。例如,如果 $c_j=(x_1 \lor x_2 \lor ...)$ 且 $x_1, x_2$ 都为真,我们既可以在 $x_1$ 菱形里绕行访问 $C_j$,也可以在 $x_2$ 菱形里绕行访问。 * 为了构造一条哈密顿路径(每个节点只访问一次),我们只需要为每个子句节点 $C_j$ **选择一次**绕行即可。随便选哪个可用的机会都行。 10. **“因此,我们构造了所需的哈密顿路径。”**: * 我们从一个满足赋值出发,构造了一条路径。这条路径从 $s$ 到 $t$,按顺序访问了所有菱形内部的全部节点,并且通过为每个子句选择一个满足它的真文字,找到了一条对应的绕行路径,从而访问了所有子句节点。 * 最终,这条路径访问了图中的所有节点,且每个节点恰好一次。因此,它是一条哈密顿路径。证明完毕。 [具体数值示例] * **公式**: $\phi = (x_1 \lor \overline{x_2}) \wedge (x_2 \lor x_3)$ * **满足赋值**: $x_1=$ 真, $x_2=$ 真, $x_3=$ 假。 * **路径构造**: 1. **主干路径方向**: * $x_1$ 为真:在菱形1中“从左到右”走。 * $x_2$ 为真:在菱形2中“从左到右”走。 * $x_3$ 为假:在菱形3中“从右到左”走。 2. **子句满足情况**: * $c_1 = (x_1 \lor \overline{x_2})$: $x_1$ 为真,满足 $c_1$。 * $c_2 = (x_2 \lor x_3)$: $x_2$ 为真,满足 $c_2$。 3. **选择绕行**: * **对于 $C_1$**: 我们选择用真文字 $x_1$ 来访问它。因为 $x_1$ 为真,路径在菱形1中从左到右走。当走到为 $c_1$ 预留的节点对时,路径可以使用“左进右出”的岔路去访问 $C_1$。 * **对于 $C_2$**: 我们选择用真文字 $x_2$ 来访问它。因为 $x_2$ 为真,路径在菱形2中从左到右走。当走到为 $c_2$ 预留的节点对时,路径可以使用“左进右出”的岔路去访问 $C_2$。 * **最终路径**: 一条从 $s$ 开始,按“左到右”方式穿过菱形1(中途绕行访问 $C_1$),然后按“左到右”方式穿过菱形2(中途绕行访问 $C_2$),再按“右到左”方式穿过菱形3,最后到达 $t$ 的路径。这条路径访问了所有节点,是一条哈密顿路径。 [易错点与边界情况] * **“之字形”的误导**: 图 7.53 中画出的“之字形”路径可能暗示水平链有两行节点。更简单的理解是,无论内部如何“之字”,其关键作用就是提供了两种从头到尾的遍历方式(左到右/右到左),并且路径方向决定了哪种岔路(正文字/负文字)是可用的。 * **只绕行一次**: 强调只为每个子句节点选择一次绕行,是保证路径简单性(不重复访问节点)的关键。 [总结] 本段完成了 **HAMPATH** 归约正确性证明的第一个方向。它展示了如何将一个已知的 **3SAT** 满足赋值,系统地“翻译”成一条哈密顿路径。该过程分为两步:首先,根据变量的真假值确定穿越每个菱形主干道的方向(左到右/右到左);然后,利用每个子句都至少有一个真文字这一事实,为每个子句节点选择一个可用的“绕行岔路”将其并入主路径。最终构造出的路径覆盖了图中所有节点,从而证明了哈密顿路径的存在性。 [存在目的] 本段的目的是为了严谨地证明“可满足 $\Rightarrow$ 哈密顿路径”。它将之前描述的、看似静态的图结构动态化,展示了路径如何在这些结构中流动,以及这种流动是如何精确地被布尔赋值所控制的。这是连接逻辑世界和图论世界的关键桥梁之一。 [直觉心-模型] 回到特技飞行挑战: * **前提**: 你已经找到了一套完美的航线选择方案(满足赋值),可以让你撞破所有气球。 * **路径构造**: 1. 你为每个菱形峡谷(变量)确定了飞行方式(“Z”字形或反“Z”字形),对应变量的真假。 2. 对于每个目标气球(子句),因为你的方案是完美的,所以你至少有一条通往它的“侧飞”航线是可用的。 3. 你为每个气球只选择一条侧飞航线来撞破它。 4. 你将所有这些飞行路线(主航线+侧飞)串联起来,就得到了一条从起点到终点,飞越所有峡谷,撞破所有气球的完整、不重复的飞行路径。这就是哈密顿路径。 [直观想象] 你是一位城市规划师,正在验证一份“完美交通流”方案(满足赋值)。 * **方案**: 方案为城市里每条“二选一”的单行道(变量菱形)都指定了当天的行驶方向。 * **验证**: 1. 你根据方案,绘制出主干道的交通流。 2. 这个城市里有 $k$ 个必须打卡的“地标”(子句节点)。 3. 由于方案是完美的,对于每个地标,都至少有一条从主干道出发的“观景环路”是顺行的。 4. 你规划一条公交线路:沿着主干道交通流行驶,每到一个地标对应的“观景环路”路口,如果环路是顺行的,就开进去打个卡再出来(只为每个地标打卡一次)。 5. 你最终画出的这条公交线路,就是一条访问了城市里所有路口(节点)的哈密顿路径。 ### 3.4.8. 正确性证明(二):哈密顿路径 $\Rightarrow$ 可满足 [原文] 对于反方向,如果 $G$ 有一条从 $s$ 到 $t$ 的哈密顿路径,我们演示 $\phi$ 的一个满足赋值。如果哈密顿路径是正常的——即,除了到子句节点的绕行之外,它按顺序从上到下穿过菱形——我们可以很容易地获得满足赋值。如果路径之字形穿过菱形,我们将相应的变量赋值为 TRUE;如果它反之字形穿过,我们赋值为 FALSE。因为每个子句节点都出现在路径上,通过观察它是如何绕行到达的,我们可以确定相应子句中的哪个文字为真。 剩下的就是证明哈密顿路径必须是正常的。非正常情况只可能发生:路径从一个菱形进入一个子句节点,但返回到另一个菱形,如下图所示。 ![](https://cdn.mathpix.com/cropped/0a1d72f2-fd58-445d-af2f-6f8996f4f919-44.jpg?height=558&width=573&top_left_y=1125&top_left_x=618) 图 7.54 这种情况不可能发生 路径从节点 $a_{1}$ 到 $c$;但它不是返回到同一菱形中的 $a_{2}$,而是返回到不同菱形中的 $b_{2}$。如果发生这种情况,$a_{2}$ 或 $a_{3}$ 必须是分隔节点。如果 $a_{2}$ 是分隔节点,那么进入 $a_{2}$ 的唯一边将来自 $a_{1}$ 和 $a_{3}$。如果 $a_{3}$ 是分隔节点,$a_{1}$ 和 $a_{2}$ 将在同一子句对中,因此进入 $a_{2}$ 的唯一边将来自 $a_{1}$、$a_{3}$ 和 $c$。在任何一种情况下,路径都不能包含节点 $a_{2}$。路径不能从 $c$ 或 $a_{1}$ 进入 $a_{2}$,因为路径从这些节点去往别处。路径不能从 $a_{3}$ 进入 $a_{2}$,因为 $a_{3}$ 是 $a_{2}$ 指向的唯一可用节点,所以路径必须通过 $a_{3}$ 离开 $a_{2}$。因此,哈密顿路径必须是正常的。这个归约显然在多项式时间内完成,证明完毕。 [逐步解释] 这部分证明了更难的另一个方向:如果图中存在一条哈密顿路径,那么我们一定能据此构造出 $\phi$ 的一个满足赋值。 1. **“如果 $G$ 有一条从 $s$ 到 $t$ 的哈密顿路径,我们演示 $\phi$ 的一个满足赋值。”**: 这是本部分的目标。 2. **“如果哈密顿路径是正常的...我们可以很容易地获得满足赋值。”**: * 首先,定义什么是“**正常路径**”:一条路径,它严格按照 $s \to \text{菱形}_1 \to \text{菱形}_2 \to \cdots \to t$ 的顺序前进,唯一的“偏离”是从某个菱形内部出去访问一个子句节点,然后**必须立即返回**到它出发的那个菱形中,继续前进。 * 如果路径是“正常的”,构造赋值就非常直接: * **赋值**: 观察路径穿过每个菱形 $i$ 的方向。如果它是“从左到右”走的,我们就令 $x_i = $ 真。如果它是“从右到左”走的,我们就令 $x_i = $ 假。 * **验证满足性**: 因为路径是哈密顿路径,它必须访问了每一个子句节点 $C_j$。由于路径是“正常的”,对 $C_j$ 的访问必然是通过某个菱形 $i$ 中的岔路完成的。 * 如果这个岔路是“左进右出”型的,说明路径在菱形 $i$ 中是“从左到右”走的,我们已令 $x_i=$ 真。而这个岔路的存在本身就意味着子句 $c_j$ 包含正文字 $x_i$。因此,该赋值满足 $c_j$。 * 如果这个岔路是“右进左出”型的,说明路径在菱形 $i$ 中是“从右到左”走的,我们已令 $x_i=$ 假。而这个岔路的存在意味着子句 $c_j$ 包含负文字 $\overline{x_i}$。因此,该赋值也满足 $c_j$。 * 由于每个子句节点都被访问了,所以每个子句都被满足了。因此 $\phi$ 可满足。 3. **“剩下的就是证明哈密顿路径必须是正常的。”**: * 这是证明的 crux (关键点)。我们必须排除所有“非正常”走法的可能性。 * **什么是非正常路径?** 最主要的非正常情况是:路径从一个菱形(比如菱形 $i$)出发访问了子句节点 $C_j$,但没有返回菱形 $i$,而是“跳”到了另一个菱形(比如菱形 $k$)中。如图 7.54 所示。 4. **对图 7.54 的分析(排除非正常路径)**: * **场景**: 路径沿着 $... \to a_1 \to c$ 行进,其中 $a_1$ 在一个菱形里, $c$ 是子句节点。然后路径没有走 $c \to a_2$ 返回同一个菱形,而是走了 $c \to b_2$ 跳到了另一个菱形的 $b_2$ 节点。 * **问题**: 节点 $a_2$ 怎么办?由于这是一条哈密顿路径,它最终必须以某种方式访问 $a_2$。 * **分析 $a_2$ 的入度**: 有哪些边是指向 $a_2$ 的? * 来自它在水平链上的邻居,即 $a_1$ 和 $a_3$ (这里的 $a_3$ 是 $a_2$ 在链上的另一个邻居)。 * 可能来自某个子句节点的返回边,例如 $c \to a_2$。 * **路径的约束**: * 路径已经从 $a_1$ 走到了 $c$,所以不可能再从 $a_1$ 走到 $a_2$ 了(一个节点只有一个后继)。 * 路径已经从 $c$ 走到了 $b_2$,所以不可能再从 $c$ 走到 $a_2$ 了。 * 所以,要访问 $a_2$,路径必须从它的另一个邻居 $a_3$ 进入,即 $... \to a_3 \to a_2$。 * **矛盾所在**: * 原文的论证有点绕,但核心思想是:**分隔节点 (separator node)** 的设计使得这种跳跃不可能。 * 让我们更清晰地阐述:在节点对 $(a_1, a_2)$ 和 $(b_1, b_2)$ 之间,必然存在至少一个分隔节点。分隔节点的特殊之处在于,它在水平链上的入度和出度都是1(只和左右两个邻居相连)。它没有任何连接到子句节点的“岔路”。 * 如果路径要从 $c$ 跳到 $b_2$,那么它之后必须继续走完 $b$ 菱形剩下的部分。然后它需要再跳回到 $a$ 菱形,去收拾剩下的节点(比如 $a_2$)。 * 但分隔节点的设计使得这种“菱形间”的跳跃只能通过子句节点进行。当你用完了所有子句节点的“桥梁”后,你可能会发现自己被困在一个菱形里,无法去访问另一个菱形里剩下的“孤岛”节点。 * 原文的论证“路径不能从 $a_3$ 进入 $a_2$,因为 $a_3$ 是 $a_2$ 指向的唯一可用节点,所以路径必须通过 $a_3$ 离开 $a_2$” 比较费解,但其本质是,一旦路径的选择使得 $a_2$ 这样的节点被“孤立”出来(它的所有入口都被之前的路径占用了),那么哈密顿路径就不可能存在。分隔节点的设计,就是为了确保任何试图“跳跃”的路径都会导致某些节点被如此“孤立”。 5. **“因此,哈密顿路径必须是正常的。”**: 基于上述(虽然原文描述得有些晦涩)的排除法,我们得出结论,任何存在于该图中的哈密顿路径都必须遵循我们定义的“正常”模式。 6. **“这个归约显然在多项式时间内完成,证明完毕。”**: * **多项式时间**: 构造图 $G$ 的时间复杂度是多少? * 节点数: $2 + l \times (3k+1+2) + k \approx O(lk)$。 * 边数: 也大致是 $O(lk)$ 级别。 * 公式 $\phi$ 的大小 $n$ 大致是 $l+k$。因此图的大小是关于 $n$ 的二次多项式。构造过程是简单的节点和边添加,所以是多项式时间的。 * **证明完毕**: 两个方向的等价性都已证明,且归约是多项式时间的,因此 **3SAT** $\le_P$ **HAMPATH** 成立。结合 **HAMPATH** $\in$ **NP**,定理 7.46 得证。 [易错点与边界情况] * **对“正常路径”的理解**: 理解“正常路径”的定义,以及为什么它是我们能够从路径反推赋值的关键,是理解本部分证明的核心。 * **分隔节点的作用**: 本部分证明的难点在于理解分隔节点是如何防止“跳跃”的。虽然原文的解释不易懂,但其核心作用是**局部化**子句的绕行,确保“出差”访问子句节点后必须“返回原单位”。 * **归约的艺术性**: 这个归约非常精妙,它用图的拓扑结构(连接性、方向性)完美地模拟了抽象的逻辑约束。它的正确性高度依赖于每一个细节(节点数、边的方向、分隔节点)都恰到好处。 [总结] 本段证明了 **HAMPATH** 归约的第二个、也是更困难的方向:从一条已知的哈密顿路径反向构造出原 **3SAT** 公式的满足赋值。证明的关键在于,首先论证了任何存在于此图中的哈密顿路径都必须是“正常的”(即严格按顺序穿越菱形,且对子句的访问是“哪里去哪里回”的绕行)。基于此,我们可以根据路径穿越每个菱形的方向(左到右/右到左)来确定变量的真假赋值。因为路径访问了所有子句节点,这意味着每个子句都通过某个可用的绕行被“满足”了,从而证明了该赋值方案的有效性。最后,它确认了整个归约构造过程能在多项式时间内完成,从而完成了 **HAMPATH** 的 **NP-完全**性证明。 [存在目的] 本段的目的是为归约的正确性提供最后也是最关键的一块拼图。它确保了我们构造的图不会因为存在某些“取巧”的路径(非正常路径)而导致逻辑等价性被破坏。通过严格证明所有可能的路径都必须是我们期望的“正常”形式,它封堵了所有可能的漏洞,使得从路径到赋值的映射成为可能,从而完成了整个双向的逻辑链条。 [直觉心智模型] 回到特技飞行挑战: * **前提**: 你找到了一条能飞越所有峡谷、撞破所有气球的哈密顿飞行路径。 * **证明路径必须正常**: 你发现,因为峡谷之间的连接非常稀疏(只有主航道),而且每个峡谷内部的航线设计(特别是分隔区域)让你无法在一个峡谷的“侧飞点”出去后,飞到另一个峡谷的“侧飞点”去。任何这样尝试的后果,都会导致你漏掉出发峡谷里的某个区域无法返回。因此,你得出结论:任何成功的完整路径,都必须是“进入峡谷A-飞完峡谷A(中途可侧飞撞气球并返回)-离开峡谷A进入峡谷B...”。 * **构造赋值**: 1. 你记录下你的路径在每个峡谷里的飞行方式(“Z”形还是反“Z”形)。这就是你的变量赋值。 2. 因为你撞破了所有气球,你知道这个赋值方案是有效的,它为每个气球都提供了至少一条可用的侧飞航线。 3. 因此,你从一条成功的飞行路径,反向推导出了一个可行的航线选择方案(满足赋值)。 [直观想象] 你得到了一份完整的、通过了迷宫的路线图(哈密顿路径)。 * **路径的正常性**: 你研究地图后发现,迷宫的设计(特别是那些狭窄的“隔离走廊”,即分隔节点)使得你不可能从一个大厅(菱形)的某个房间(节点对)出去后,直接跑到另一个大厅的房间里。唯一的通道就是预设的主路。所以,路线图必然是完整地走完一个大厅,再走向下一个大厅。 * **推导谜题答案**: 1. 你根据路线图在每个“菱形大厅”里是“从左到右”还是“从右到左”走的,来确定逻辑谜题中每个变量的答案(真或假)。 2. 你看到路线图访问了所有的“关键房间”(子句节点)。你检查它是从哪个大厅的哪条路绕过去访问的,这正好告诉你,你推导出的这个答案,是如何满足谜题中对应的那个条件的。 3. 最终,你从一张行走路线图,成功地破解了整个逻辑谜题的答案。 # 4. 无向哈密顿路径问题 ## 4.1. UHAMPATH 的 NP-完全性 [原文] ## 定理 7.55 **UHAMPATH** 是 **NP**-完全的。 证明 归约接受一个带有节点 $s$ 和 $t$ 的有向图 $G$,并构造一个带有节点 $s^{\prime}$ 和 $t^{\prime}$ 的无向图 $G^{\prime}$。图 $G$ 具有从 $s$ 到 $t$ 的哈密顿路径当且仅当 $G^{\prime}$ 具有从 $s^{\prime}$ 到 $t^{\prime}$ 的哈密顿路径。我们描述 $G^{\prime}$ 如下。 $G$ 的每个节点 $u$,除了 $s$ 和 $t$,都被 $G^{\prime}$ 中的三元组节点 $u^{\text {in }}$、$u^{\text {mid }}$ 和 $u^{\text {out }}$ 替换。$G$ 中的节点 $s$ 和 $t$ 被 $G^{\prime}$ 中的节点 $s^{\text {out }}=s^{\prime}$ 和 $t^{\text {in }}=t^{\prime}$ 替换。$G^{\prime}$ 中出现两种类型的边。首先,边连接 $u^{\text {mid }}$ 与 $u^{\text {in }}$ 和 $u^{\text {out }}$。其次,如果 $G$ 中有从 $u$ 到 $v$ 的边,则边连接 $u^{\text {out }}$ 与 $v^{\text {in }}$。这样就完成了 $G^{\prime}$ 的构造。 [逐步解释] 这部分开始证明 **哈密顿路径问题** 的无向版本(**UHAMPATH**)也是 **NP-完全**的。其采用的策略是从已知的 **NP-完全**问题 **HAMPATH** (有向版) 进行归约。 1. **“定理 7.55 UHAMPATH 是 NP-完全的。”**: * **UHAMPATH**: 输入是一个**无向图** $G$ 和两个节点 $s, t$,问是否存在一条从 $s$ 到 $t$ 的、经过所有节点恰好一次的路径。 * 这个定理宣告了,即使把边的方向去掉,问题本质的难度并未降低。 2. **“证明 归约接受一个带有节点 $s$ 和 $t$ 的有向图 $G$,并构造一个...无向图 $G^{\prime}$...”**: * **归约方向**: **HAMPATH** $\le_P$ **UHAMPATH**。 * **输入**: 一个 **HAMPATH** 问题的实例,即一个有向图 $G$ 和起终点 $s, t$。 * **输出**: 一个 **UHAMPATH** 问题的实例,即一个无向图 $G'$ 和起终点 $s', t'$。 * **目标**: 证明 $G$ 有哈密顿路径 $\iff G'$ 有哈密顿路径。 3. **$G'$ 的构造——节点替换**: * 这是一个典型的“节点小工具”构造。我们用一个更复杂的结构来替换原来图中的每个简单节点,以在无向图中模拟有向图的行为。 * **对于中间节点**: $G$ 中的每个普通节点 $u$ (既不是 $s$ 也不是 $t$),在 $G'$ 中都被替换成一个由三个节点组成的“三元组”:$u^{in}, u^{mid}, u^{out}$。 * **对于起点 $s$**: $G$ 中的起点 $s$ 在 $G'$ 中被替换成一个单节点 $s^{out}$,这个节点同时也是 $G'$ 的新起点 $s'$。 * **对于终点 $t$**: $G$ 中的终点 $t$ 在 $G'$ 中被替换成一个单节点 $t^{in}$,这个节点同时也是 $G'$ 的新终点 $t'$。 4. **$G'$ 的构造——边的添加**: * **第一类边 (内部连接)**: 在每个三元组内部,我们将中间节点 $u^{mid}$ 与它的两个“邻居” $u^{in}$ 和 $u^{out}$ 连接。由于 $G'$ 是无向图,这两条边是 $(u^{mid}, u^{in})$ 和 $(u^{mid}, u^{out})$。这形成了一个形如 $u^{in} - u^{mid} - u^{out}$ 的短路径。 * **第二类边 (外部连接)**: 这类边模拟了原图 $G$ 的有向边。如果 $G$ 中有一条有向边 $u \to v$,我们就在 $G'$ 中添加一条无向边,连接 $u$ 的“出口”和 $v$ 的“入口”,即边 $(u^{out}, v^{in})$。 5. **构造完成**: * 将 $G$ 的所有节点按规则替换,并根据 $G$ 的所有有向边添加对应的无向边后,$G'$ 的构造就完成了。这个过程显然是多项式时间的。 [具体数值示例] * **输入有向图 $G$**: 节点 $\{s, u, v, t\}$,有向边 $s \to u, u \to v, v \to t$。这是一个简单的有向路径。 * **输出无向图 $G'$**: * **节点 (8个)**: * $s$ 替换为 $s^{out}$ (即 $s'$) * $u$ 替换为 $u^{in}, u^{mid}, u^{out}$ * $v$ 替换为 $v^{in}, v^{mid}, v^{out}$ * $t$ 替换为 $t^{in}$ (即 $t'$) * **边**: * **内部边**: $(u^{in}, u^{mid}), (u^{mid}, u^{out}), (v^{in}, v^{mid}), (v^{mid}, v^{out})$。 * **外部边**: * 因为 $s \to u$,添加边 $(s^{out}, u^{in})$。 * 因为 $u \to v$,添加边 $(u^{out}, v^{in})$。 * 因为 $v \to t$,添加边 $(v^{out}, t^{in})$。 * **$G'$ 的样子**: 整个图 $G'$ 看起来像一条链: $s^{out} - u^{in} - u^{mid} - u^{out} - v^{in} - v^{mid} - v^{out} - t^{in}$。 这显然是一条哈密顿路径。 [易错点与边界情况] * **小工具的目的**: 这个 $u^{in} - u^{mid} - u^{out}$ 结构的核心作用是在无向图中强加一个“方向”。任何想要访问 $u^{mid}$ 的哈密顿路径,都必须从 $u^{in}$ 和 $u^{out}$ 中的一个进入,并从另一个离开。它不能从别的地方跳到 $u^{mid}$。这模拟了路径必须“流经”节点 $u$ 的行为。 * **起点和终点的特殊处理**: 起点 $s$ 只有“出口” $s^{out}$,终点 $t$ 只有“入口” $t^{in}$。这确保了路径在 $G'$ 中也必须从 $s$ 的对应部分开始,在 $t$ 的对应部分结束。 [总结] 本段提出了 **UHAMPATH** 的 **NP-完全**性证明,其策略是构造一个从 **HAMPATH** 到 **UHAMPATH** 的多项式时间归约。该归约的核心是设计了一个“三元组”节点小工具 $(u^{in}, u^{mid}, u^{out})$ 来替换原图中的每个节点 $u$。这个小工具通过内部连接 $(u^{in} - u^{mid} - u^{out})$ 强制路径必须“流经”它,而外部连接则通过连接前后节点的“出口”和“入口” $(u^{out}, v^{in})$ 来模拟原图中的有向边。这样,一个有向图就被转换成了一个行为上等价的无向图。 [存在目的] 本段的目的是展示 **NP-完全**性的“传染”过程。一旦我们有了一个已知的 **NP-完全**问题(**HAMPATH**),我们就可以利用它作为“跳板”,去证明其他相关问题的 **NP-完全**性。这个证明比从 **3SAT** 直接归约到 **UHAMPATH** 要简单得多,因为它处理的是两个结构相似的图论问题。它也再次展示了“小工具”思想的强大威力,即通过设计局部结构来模拟和强制特定的行为。 [直觉心智模型] 想象你要把一个“单行道”网络(有向图)改造成一个“双行道”网络(无向图),但又要保留原来的单向交通流规则。 * **节点改造(三元组小工具)**: 你把原来的每个十字路口 $u$,都改造成一个微型环岛,有三个出入口:一个“入口匝道”($u^{in}$),一个“环岛主体”($u^{mid}$),一个“出口匝道”($u^{out}$)。车流必须从入口匝道进,经过环岛主体,再从出口匝道出。 * **道路改造(外部连接)**: 原来从路口 $u$ 到路口 $v$ 的一条单行道,现在你把它改建成一条连接 $u$ 的“出口匝道”和 $v$ 的“入口匝道”的双行道。 * **效果**: 虽然所有道路都是双行的,但由于每个路口都被改造成了“必须按顺序通过”的微型环岛,任何想要走遍所有路口的司机,实际上还是被迫遵循了原来单行道网络的流向。 [直观想象] 你有一串磁珠,磁珠有 N 极和 S 极(有向)。你想用一串不分极性的普通铁珠(无向)来模拟它。 * **磁珠 $u$ 的替换**: 你用三颗铁珠来代替一颗磁珠 $u$:一颗叫 $u_{in}$,一颗叫 $u_{mid}$,一颗叫 $u_{out}$。你用短线把它们串成 $u_{in}-u_{mid}-u_{out}$。 * **连接**: 原来磁珠 $u$ 的 S 极连接到磁珠 $v$ 的 N 极,现在你用一根长线把铁珠串 $u$ 的尾巴($u_{out}$)和铁珠串 $v$ 的头($v_{in}$)连起来。 * **效果**: 虽然所有铁珠和线都是无方向的,但任何一条想要走遍所有铁珠的路径,都必须沿着 $u_{in} \to u_{mid} \to u_{out}$ 的顺序穿过每一个三珠串。这就在无方向的系统中,重现了有方向的流动。 ## 4.2. UHAMPATH 归约的正确性证明 [原文] 我们可以通过证明 $G$ 具有从 $s$ 到 $t$ 的哈密顿路径当且仅当 $G^{\prime}$ 具有从 $s^{\text {out }}$ 到 $t^{\text {in }}$ 的哈密顿路径来证明这个构造是有效的。为了证明一个方向,我们观察到 $G$ 中的哈密顿路径 $P$, $$

s, u_{1}, u_{2}, \ldots, u_{k}, t,

$$ 在 $G^{\prime}$ 中有相应的哈密顿路径 $P^{\prime}$, $$

s^{\text {out }}, u_{1}^{\text {in }}, u_{1}^{\text {mid }}, u_{1}^{\text {out }}, u_{2}^{\text {in }}, u_{2}^{\text {mid }}, u_{2}^{\text {out }}, \ldots, t^{\text {in }} .

$$ 为了证明另一个方向,我们声称 $G^{\prime}$ 中从 $s^{\text{out}}$ 到 $t^{\text{in}}$ 的任何哈密顿路径必须从一个三元组节点到另一个三元组节点,除了起点和终点,就像我们刚刚描述的路径 $P^{\prime}$ 一样。这将完成证明,因为任何这样的路径在 $G$ 中都有相应的哈密顿路径。我们通过从节点 $s^{\text{out}}$ 开始跟踪路径来证明这个论断。观察到路径中的下一个节点必须是某个 $i$ 的 $u_{i}^{\text{in}}$,因为只有这些节点与 $s^{\text{out}}$ 连接。下一个节点必须是 $u_{i}^{\text{mid}}$,因为没有其他方式可以将 $u_{i}^{\text{mid}}$ 包含在哈密顿路径中。在 $u_{i}^{\text{mid}}$ 之后是 $u_{i}^{\text{out}}$,因为这是 $u_{i}^{\text{mid}}$ 连接的唯一其他节点。下一个节点必须是某个 $j$ 的 $u_{j}^{\text{in}}$,因为没有其他可用节点连接到 $u_{i}^{\text{out}}$。论证然后重复直到到达 $t^{\text{in}}$。 [逐步解释] 这部分对 **HAMPATH 到 UHAMPATH** 的归约进行了双向的正确性证明。 **第一部分:证明 $G$ 有哈密顿路径 $\Rightarrow G'$ 有哈密顿路径** 1. **“我们观察到 $G$ 中的哈密顿路径 $P$...在 $G'$ 中有相应的哈密顿路径 $P'$”**: 这是一个构造性的证明。 2. **给定的 $G$ 中的路径 $P$**: $s, u_1, u_2, \ldots, u_k, t$。这表示 $G$ 中存在有向边 $s \to u_1$, $u_1 \to u_2$, ..., $u_k \to t$。 3. **构造 $G'$ 中的路径 $P'$**: 我们将 $P$ 中的每个节点“展开”。 * $s$ 变成 $s^{out}$。 * 每个 $u_i$ 变成路径片段 $u_i^{in} - u_i^{mid} - u_i^{out}$。 * $t$ 变成 $t^{in}$。 4. **拼接路径 $P'$**: * 路径从 $s^{out}$ 开始。 * 由于 $G$ 中有边 $s \to u_1$,根据构造,$G'$ 中有边 $(s^{out}, u_1^{in})$。所以路径可以走到 $u_1^{in}$。 * 然后路径必须走完 $u_1$ 的三元组:$u_1^{in} - u_1^{mid} - u_1^{out}$。 * 由于 $G$ 中有边 $u_1 \to u_2$,根据构造,$G'$ 中有边 $(u_1^{out}, u_2^{in})$。所以路径可以从 $u_1$ 的出口走到 $u_2$ 的入口。 * 这个过程不断重复,直到路径走到 $u_k^{out}$。 * 由于 $G$ 中有边 $u_k \to t$,根据构造,$G'$ 中有边 $(u_k^{out}, t^{in})$。路径最终到达 $t^{in}$。 5. **验证 $P'$ 是哈密顿路径**: * **覆盖所有节点**: 原始路径 $P$ 覆盖了 $G$ 的所有节点。我们构造的 $P'$ 相应地访问了 $s^{out}, t^{in}$ 以及每一个三元组 $u_i^{in}, u_i^{mid}, u_i^{out}$。由于 $G'$ 的节点就是由这些部分组成的,所以 $P'$ 覆盖了 $G'$ 的所有节点。 * **每个节点一次**: 构造过程是线性的,没有回头路,所以每个节点只访问一次。 * 因此,$P'$ 是一条 $G'$ 中的哈密顿路径。 **第二部分:证明 $G'$ 有哈密顿路径 $\Rightarrow G$ 有哈密顿路径** 1. **“我们声称 $G'$ 中从 $s^{\text{out}}$ 到 $t^{\text{in}}$ 的任何哈密顿路径必须...就像我们刚刚描述的路径 $P'$ 一样。”**: 这是关键断言。它说明 $G'$ 的结构非常严格,只允许一种“标准形式”的哈密顿路径。 2. **证明这个断言 (通过追踪路径)**: * **起点**: 路径从 $s^{out}$ 开始。 * **第1步**: $s^{out}$ 的邻居有哪些?根据构造,它只与那些满足“$G$ 中有边 $s \to u_i$”的节点的入口 $u_i^{in}$ 相连。所以路径的下一个节点**必须**是某个 $u_i^{in}$。 * **第2步**: 现在路径在 $u_i^{in}$。它的邻居是 $s^{out}$ (已访问) 和 $u_i^{mid}$。为了能继续前进并最终访问所有节点,它必须走向 $u_i^{mid}$。更重要的是,节点 $u_i^{mid}$ 的度为2,它的邻居只有 $u_i^{in}$ 和 $u_i^{out}$。任何哈密顿路径要访问 $u_i^{mid}$,都必须从一端进,另一端出,形成 $...-u_i^{in}-u_i^{mid}-u_i^{out}-...$ 或 $...-u_i^{out}-u_i^{mid}-u_i^{in}-...$ 的子路径。由于路径刚从 $s^{out}$ 到达 $u_i^{in}$,所以它别无选择,只能走向 $u_i^{mid}$。 * **第3步**: 路径在 $u_i^{mid}$。它的另一个邻居是 $u_i^{out}$。路径必须走向 $u_i^{out}$。 * **第4步**: 路径在 $u_i^{out}$。它的邻居有哪些?有 $u_i^{mid}$ (已访问),以及所有满足“$G$ 中有边 $u_i \to u_j$”的节点的入口 $u_j^{in}$。为了继续哈密顿路径,它必须走向某个新的、未访问的 $u_j^{in}$。 * **重复**: 这个 $u_j^{in} \to u_j^{mid} \to u_j^{out}$ 的过程会一直重复。 * **结论**: 这证明了 $G'$ 中的任何哈密顿路径都必须遵循“从一个三元组的出口,跳到下一个三元组的入口”的模式。 3. **从 $G'$ 的路径构造 $G$ 的路径**: * 既然 $G'$ 的哈密顿路径形如 $s^{out} - (u_1 \text{三元组}) - (u_2 \text{三元组}) - \dots - t^{in}$,我们可以直接从中读取出 $G$ 中的路径。 * $s^{out}$ 对应 $s$。 * $(u_1 \text{三元组})$ 对应 $u_1$。 * ... * $t^{in}$ 对应 $t$。 * $G'$ 中存在边 $(u_i^{out}, u_{i+1}^{in})$,这根据构造规则,意味着 $G$ 中存在有向边 $u_i \to u_{i+1}$。 * 因此,我们从 $G'$ 的路径 $P'$ 中提取出的节点序列 $s, u_1, u_2, \ldots, t$ 在 $G$ 中是一条合法的路径。 * 由于 $P'$ 访问了所有三元组,所以提取出的路径也访问了 $G$ 的所有节点。因此,它是 $G$ 中的一条哈密顿路径。 [总结] 本段严谨地证明了 **HAMPATH 到 UHAMPATH** 归约的正确性。 * **正向证明**通过一个直接的构造,展示了如何将有向图中的一条哈密顿路径“翻译”成无向图中一条等价的哈密顿路径,方法是简单地展开每个节点为三元组。 * **反向证明**则通过分析无向图 $G'$ 的结构约束,论证了任何存在于 $G'$ 中的哈密顿路径都必须遵循一种固定的“流式”模式。这种模式使得我们可以从中唯一地反向“读取”出一条在原有向图 $G$ 中合法的哈密顿路径。两个方向的证明共同确立了两个问题实例之间的等价性。 [存在目的] 本段的目的是完成 **UHAMPATH** 的 **NP-完全**性证明。在上一段描述了归约的“如何做”(构造方法)之后,这一段回答了“为什么行”(正确性证明)。这是任何归约证明中必不可少的核心部分,它确保了我们建立的“问题转换机”是可靠的,没有逻辑漏洞。 [直觉心智模型] 回到改造单行道网络的比喻: * **正向证明**: 如果你有一张地图,标明了如何在单行道网络里走遍所有路口。你只要按照这个顺序,依次穿过每个路口改造后的“微型环岛”(入口匝道-环岛主体-出口匝道),就能在新的双行道网络里,同样走遍所有地方。 * **反向证明**: 如果你在新的双行道网络里找到了一条走遍所有地方的路线。你观察这条路线,发现它在每个“微型环岛”处,都只能是“从入口匝道进,从出口匝道出”。你把这些“环岛”的名字按顺序记下来,就得到了一条在原始单行道网络里完全合法的路线。因为你在新网络里走了所有地方,所以这条原始路线也一定经过了所有路口。 [直观想象] 回到用铁珠模拟磁珠的比喻: * **正向证明**: 如果你有一串按特定顺序排列的磁珠链。你只要把每个磁珠都换成对应的“三珠串”,再把这些三珠串按原来的顺序连起来,你就得到了一条包含所有铁珠的、完整的铁珠链。 * **反向证明**: 现在你手里有一条由许多“三珠串”和连接线组成的、完整的铁珠长链。你观察发现,这条长链的路径在每个“三珠串”内部,都必须是 $in \to mid \to out$。于是你把每个“三珠串”都看作一个整体,你得到的序列就对应一条原始的磁珠链。因为铁珠链是完整的,所以磁珠链也一定是完整的。 # 5. 子集和问题 ## 5.1. 问题定义回顾 [原文] ## **子集和问题** 回想一下第 297 页定义的 **子集和问题**。在该问题中,我们给定一组数字 $x_{1}, \ldots, x_{k}$ 以及一个目标数字 $t$,并要求确定该集合是否包含一个子集合,其元素之和为 $t$。现在我们证明这个问题是 **NP**-完全的。 [逐步解释] 这部分再次引入了一个新的问题——**子集和问题 (SUBSET-SUM)**,并预告了将要证明其 **NP-完全**性。 1. **“子集和问题 (SUBSET-SUM)”**: 问题的名称。这是一个经典的组合优化和计算复杂性问题。 2. **“回想一下第 297 页定义的...”**: 表明这个问题在本书前面已经介绍过。 3. **问题定义**: * **输入**: 1. 一个集合(或多重集)$S = \{x_1, x_2, \ldots, x_k\}$,由 $k$ 个数字组成。这些数字可以是整数,通常是非负整数。 2. 一个目标值 $t$。 * **问题**: 判断是否存在 $S$ 的一个子集 $S' \subseteq S$,使得 $S'$ 中所有元素的和恰好等于 $t$。 * 这是一个**判定问题**,答案是“是”或“否”。 4. **“现在我们证明这个问题是 NP-完全的。”**: 明确了本节的目标。 [具体数值示例] * **示例1:存在解** * **输入**: 集合 $S = \{3, 8, 4, 5, 2\}$,目标值 $t=10$。 * **问题**: 是否存在和为 10 的子集? * **解**: 是。子集 $\{8, 2\}$ 的和是 $8+2=10$。另一个解是 $\{3, 5, 2\}$,其和也是 $3+5+2=10$。 * **示例2:不存在解** * **输入**: 集合 $S = \{3, 8, 4, 5, 2\}$,目标值 $t=11$。 * **问题**: 是否存在和为 11 的子集? * **解**: 否。你可以尝试所有组合,都无法得到和为 11。例如,$\{8, 3\}$ 的和是 11,但 3 不在集合 S 中。哦,3 在集合 S 中,所以 $\{8,3\}$ 是一个解,和为 11。让我们换个目标值。 * **修正后的示例2**: * **输入**: 集合 $S = \{3, 8, 4, 5, 2\}$,目标值 $t=18$。 * **解**: 否。集合中所有数字的和是 $3+8+4+5+2=22$。最大的几个数 $\{8,5,4\}$ 和为 17,加上 3 就超过 18了。无法凑出 18。 [易错点与边界情况] * **判定问题 vs 优化问题**: **SUBSET-SUM** 是判定问题。它的优化版本是“背包问题 (Knapsack Problem)”,即在不超过某个容量 $t$ 的前提下,让子集的和最大。这两个问题密切相关。 * **数字的大小**: 这个问题的难度与输入数字的大小密切相关。如果数字都非常大(例如,用很多位来表示),问题会变得很困难。后面会看到,我们构造的归约正是利用了非常大的数字。存在一个伪多项式时间算法(使用动态规划)可以解决子集和问题,其时间复杂度与目标值 $t$ 和元素数量 $k$ 相关。如果 $t$ 的值相对于输入规模(数字的位数)是指数级的,那么这个算法就是指数时间的。**NP-完全**性证明说明了不存在一个时间复杂度只与 $k$ 和数字的**位数**呈多项式关系的算法。 [总结] 本段重新引入了**子集和问题 (SUBSET-SUM)** 的定义,并宣告了本节的证明目标:证明 **SUBSET-SUM** 是 **NP-完全**的。该问题询问一个给定的数字集合中,是否存在一个子集,其元素之和恰好等于一个给定的目标值。 [存在目的] 本段的作用是为后续的归约证明设定目标问题。在完成了两个图论问题的证明后,现在转向一个算术和数论风格的问题。这展示了 **NP-完全**现象的广泛性,它不仅仅局限于图论。清晰地重申问题定义,是开始一个全新风格归约证明的必要步骤。 [直觉心智模型] 想象你在超市购物,有一张面额为 $t$ 的代金券,必须正好用完,不能找零。 * **集合 S**: 超市货架上所有商品的价格标签。 * **子集和问题**: 你能否挑选一篮子商品,使得它们的价格总和正好等于你的代金券面额 $t$? * **NP-完全的含义**: 当商品种类繁多,价格各异,代金券面额也很大时,快速找到一个完美的凑单方案是非常困难的。不存在一个通用的、在所有情况下都很快的“凑单计算器”。 [直观想象] 你是一名药剂师,需要精确地配制一份重量为 $t$ 的药剂。 * **集合 S**: 你手头有各种不同重量的砝码。 * **子集和问题**: 你能否选出一些砝码,放在天平的一端,使得它们的总重量正好是 $t$? * 这个看似简单的配重问题,其内在的计算复杂性,将被证明和解决 **3SAT** 问题一样困难。 ## 5.2. 定理与证明思路 [原文] ## 定理 7.56 **SUBSET-SUM** 是 **NP**-完全的。 证明思路 我们已在定理 7.25 中证明了 **SUBSET-SUM** 属于 **NP**。我们通过将 **NP**-完全语言 3**SAT** 归约到 **SUBSET-SUM** 来证明 **NP** 中的所有语言都可以多项式时间归约到 **SUBSET-SUM**。给定一个 3 **cnf**-公式 $\phi$,我们构造一个 **SUBSET-SUM** 问题的实例,该实例包含一个子集合,其元素之和为 $t$,当且仅当 $\phi$ 是可满足的。称此子集合为 $T$。 为了实现这个归约,我们寻找 **SUBSET-SUM** 问题的结构来表示变量和子句。我们构造的 **SUBSET-SUM** 问题实例包含以十进制表示的大数字。我们用成对的数字表示变量,用十进制表示中的某些位置表示子句。 我们用两个数字 $y_{i}$ 和 $z_{i}$ 来表示变量 $x_{i}$。我们证明对于每个 $i$,要么 $y_{i}$ 要么 $z_{i}$ 必须在 $T$ 中,这建立了满足赋值中 $x_{i}$ 真值的编码。 每个子句位置在目标 $t$ 中包含一个特定值,这给子集 $T$ 施加了一个要求。我们证明这个要求与相应子句中的要求相同——即该子句中的一个文字被赋值为真。 [逐步解释] 这部分首先陈述定理,然后概述了证明 **SUBSET-SUM** 是 **NP-完全**的思路,这是一个非常巧妙的、基于数字构造的归约。 1. **“定理 7.56 SUBSET-SUM 是 NP-完全的。”**: 明确陈述最终结论。 2. **“我们已在定理 7.25 中证明了 SUBSET-SUM 属于 NP。”**: 确认了 **NP-完全**性证明的第一步已完成。验证一个子集的和是否等于 $t$ 是容易的,只需把子集中的数加起来再比较即可。 3. **“我们通过将...3SAT 归约到 SUBSET-SUM...”**: 明确了证明 **NP-难**的策略,即构造 **3SAT** $\le_P$ **SUBSET-SUM**。 4. **“...我们构造一个 SUBSET-SUM 问题的实例...当且仅当 $\phi$ 是可满足的。”**: 重申了归约的输入、输出和正确性要求。 5. **“...我们构造的 SUBSET-SUM 问题实例包含以十进制表示的大数字。”**: 揭示了**小工具**的载体。这次我们不用图的节点和边,而是用**大数字的位值**来模拟逻辑。 6. **“我们用成对的数字表示变量,用十进制表示中的某些位置表示子句。”**: 这是对**小工具**设计的核心概括。 * **变量小工具**: 一对数字 $(y_i, z_i)$。 * **子句小工具**: 数字的特定“列”或“位”。 7. **“我们用两个数字 $y_{i}$ 和 $z_{i}$ 来表示变量 $x_{i}$...”**: * 这一对数字的设计,将用来模拟变量 $x_i$ 的二元选择。 * **“要么 $y_{i}$ 要么 $z_{i}$ 必须在 $T$ 中”**: 证明的关键一步,将论证为了凑出目标和 $t$,对于每一对 $(y_i, z_i)$,我们必须且只能选择其中一个放入子集 $T$。 * 这个“二选一”的行为就完美地对应了变量 $x_i$ 必须赋值为“真”或“假”。例如,选 $y_i$ 代表 $x_i=$ 真,选 $z_i$ 代表 $x_i=$ 假。 8. **“每个子句位置在目标 $t$ 中包含一个特定值...”**: * 在大数字的表示中,我们会为每个子句 $c_j$ 分配一个专属的“数位”或“列”。 * 目标和 $t$ 在这一列上的数字是精心设置的。 * **“...这给子集 $T$ 施加了一个要求。”**: 子集 $T$ 中所有数字在这一列上的数字加起来,必须等于 $t$ 在这一列的数字。 9. **“我们证明这个要求与相应子句中的要求相同——即该子句中的一个文字被赋值为真。”**: * 这是归约的“画龙点睛”之笔。数字的设计将保证: * 只有当子句 $c_j$ 被满足时(即至少有一个对应的真文字被选中),$T$ 中数字在 $c_j$ 列上的和才能凑出 $t$ 在该列的数字。 * 这通常通过一种“无进位加法”来实现,即保证每一列的数字和不会超过9,从而不会影响到其他列,使得每一列的逻辑约束都是独立的。 [具体数值示例] * **一个极简的模拟**: * **公式**: $(x_1)$。变量 $x_1$,子句 $c_1=(x_1)$。 * **构造**: * **变量 $x_1$**: 对应两个数字 $y_1, z_1$。 * **子句 $c_1$**: 对应个位。 * **变量列**: 对应十位。 * **数字设计**: * $y_1 = 11$ (十位是1代表变量,个位是1代表它出现在$c_1$中作为$x_1$) * $z_1 = 10$ (十位是1代表变量,个位是0代表它没出现在$c_1$中作为$\overline{x_1}$) * **目标和 $t$**: $t=11$ (十位是1要求选一个变量,个位是1要求$c_1$被满足) * **求解**: * 集合 $S = \{11, 10\}$,目标 $t=11$。 * 唯一的解是子集 $\{11\}$。 * **反向推导**: * 我们选了 $y_1=11$。因为我们把“选$y_i$”对应为“$x_i$=真”。 * 所以我们得到赋值 $x_1$=真。 * 这个赋值确实满足了原公式 $(x_1)$。 * 这个例子非常简化,但展示了用不同数位来编码不同约束的基本思想。 [易错点与边界情况] * **数字的基数**: 虽然原文说“十进制”,但任何足够大的基数都可以。关键是保证在相加时,任何一列的和都不会超过基数,以避免产生进位,破坏列之间的独立性。 * **“垃圾”数字**: 后面会看到,为了让每列的和精确地达到目标值,我们还需要引入一些“填充”或“松弛”数字(slack variables),它们的作用就像是找零钱,用来补足差额。 [总结] 本段概述了将 **3SAT** 归约到 **SUBSET-SUM** 的证明思路。其核心思想是利用大数的位值来模拟逻辑:用一对数字 $(y_i, z_i)$ 的“二选一”来编码变量 $x_i$ 的赋值;用数字的特定列来代表每个子句,并通过设置目标和 $t$ 在该列的数值,来施加该子句必须被满足的约束。整个设计的精髓在于通过精巧的数字构造,使得子集的数字求和运算能够等价于布尔公式的逻辑求值,特别是通过防止进位来确保每个逻辑约束(每列)的独立性。 [存在目的] 本段的目的是在展示具体的、令人望而生畏的大数字表格之前,提供一个高层次的、概念性的解释。它告诉读者这些数字不是随机的,而是被赋予了深刻的逻辑含义。每一对数字都是一个“变量开关”,每一列都是一个“子句检查器”。这个思路解释为读者理解后续复杂的数字表格提供了“解码密钥”。 [直觉心-模型] 想象一个“配料”问题。 * **目标 $t$**: 一份最终的“魔法药水”,它要求包含:1份龙鳞,1份凤羽,...(对应变量列),以及3份A成分,3份B成分,...(对应子句列)。 * **变量 $x_i$**: 你有两瓶原料,$y_i$ 和 $z_i$。 * $y_i$ 瓶里有:1份龙鳞,以及若干其他成分(如果$x_i$出现在某个子句里)。 * $z_i$ 瓶里有:1份龙鳞,以及若干其他成分(如果$\overline{x_i}$出现在某个子句里)。 * **逻辑**: 为了凑够每种“鳞/羽”各1份,你必须从每对 $(y_i, z_i)$ 中二选一。这个选择就对应了变量赋值。 * **子句约束**: 目标药水要求A成分有3份。你通过选择 $(y,z)$ 对,可能凑了1份或2份A成分。这还不够。 * **填充数字**: 你还有一些“纯净”的A成分原料($g_j, h_j$),每份只含1份A成分。你可以用它们来补足差额,凑够3份。 * **等价性**: 你能成功配出魔法药水 $\iff$ 你对 $(y,z)$ 对的选择(变量赋值),使得每个子句列的成分初始就有至少1份,这样你才能用填充数字补到3。如果初始是0份,你最多只能补到2,任务失败。 [直观想象] 你正在填写一张特殊的调查问卷,问卷的答案需要以数字形式提交。 * **变量 $x_i$**: 对应问题“你是否同意观点 $i$?”。你有两个预设的答案数字可以选:$y_i$(代表同意)和 $z_i$(代表不同意)。 * **问卷结构**: 答案数字非常长。 * 左边的列,是“身份校验区”。 * 右边的列,是“逻辑自洽检查区”,每一列对应一个逻辑约束(子句)。 * **目标和 $t$**: 一个标准的、正确的答案总和。 * **填写规则**: * 为了通过“身份校验”(左边列的和为 $11...1$),你必须对每个问题都二选一作答。 * 为了通过“逻辑自洽检查”(右边每列的和都为3),你的选择组合必须满足所有内在的逻辑约束。例如,如果你选了代表“同意A”的数字,它会在某个检查列上加1。你必须保证每个检查列的初始和都至少是1,因为你最多只能再额外“手动”加2(通过填充数字)。 * 你能提交一份总和正确的问卷(找到子集和),当且仅当你的选择(赋值)满足了所有逻辑约束(公式可满足)。 ## 5.3. 详细证明 [原文] 证明 我们已经知道 **SUBSET-SUM** $\in \mathrm{NP}$,所以我们现在证明 3**SAT** $\leq_{\mathrm{P}}$ **SUBSET-SUM**。 令 $\phi$ 为一个布尔公式,变量为 $x_{1}, \ldots, x_{l}$,子句为 $c_{1}, \ldots, c_{k}$。归约将 $\phi$ 转换为 **SUBSET-SUM** 问题的实例 $\langle S, t\rangle$,其中 $S$ 的元素和数字 $t$ 是图 7.57 中表格的行,以普通十进制表示。双线以上的行被标记为 $$

y_{1}, z_{1}, y_{2}, z_{2}, \ldots, y_{l}, z_{l} \quad \text { 和 } \quad g_{1}, h_{1}, g_{2}, h_{2}, \ldots, g_{k}, h_{k}

$$ 并构成 $S$ 的元素。双线以下的行是 $t$。 因此,$S$ 为 $\phi$ 中的每个变量 $x_{i}$ 包含一对数字 $y_{i}, z_{i}$。这些数字的十进制表示分为两部分,如表中所示。左侧部分由一个 1 后面跟着 $l-i$ 个 0 组成。右侧部分为每个子句包含一位数字,其中 $y_{i}$ 在 $c_{j}$ 列中的数字为 1,如果子句 $c_{j}$ 包含文字 $x_{i}$;$z_{i}$ 在 $c_{j}$ 列中的数字为 1,如果子句 $c_{j}$ 包含文字 $\overline{x_{i}}$。未指定为 1 的数字为 0。 该表已部分填充,以说明示例子句 $c_{1}$、$c_{2}$ 和 $c_{k}$: $$

\left(x_{1} \vee \overline{x_{2}} \vee x_{3}\right) \wedge\left(x_{2} \vee x_{3} \vee \cdots\right) \wedge \cdots \wedge\left(\overline{x_{3}} \vee \cdots \vee \cdots\right) .

$$ 此外,$S$ 为每个子句 $c_{j}$ 包含一对数字 $g_{j}, h_{j}$。这两个数字相等,由一个 1 后面跟着 $k-j$ 个 0 组成。 最后,目标数字 $t$,即表格的最后一行,由 $l$ 个 1 后面跟着 $k$ 个 3 组成。 | | 12 | … | $c_{1}$ | $c_{2}$ | ⋯ | $c_{k}$ | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | $y_{1}$ | 1 | ⋯ | 1 | 0 | ⋯ | 0 | | $z_{1}$ | 1 | ... | 0 | 0 | … | 0 | | $y_{2}$ | 1 | ⋯ | 0 | 1 | … | 0 | | $z_{2}$ | 1 | ... | 1 | 0 | … | 0 | | $y_{3}$ | 1 | ⋯ | 1 | 1 | ⋯ | 0 | | $z_{3}$ | 1 | ⋯ | 0 | 0 | ⋯ | 1 | | ⋮ | | ⋱ | ⋮ | | ⋮ | ⋮ | | $y_{l}$ | | 1 | 0 | 0 | ⋯ | 0 | | $z_{l}$ | | 1 | 0 | 0 | … | 0 | | $g_{1}$ | | | 1 | 0 | ⋯ | 0 | | $h_{1}$ | | | 1 | 0 | ⋯ | 0 | | $g_{2}$ | | | | 1 | ⋯ | 0 | | $h_{2}$ | | | | 1 | ⋯ | 0 | | ⋮ | | | | | ⋱ | ⋮ | | $g_{k}$ | | | | | | 1 | | $h_{k}$ | | | | | | 1 | | $t$ | 1 | ⋯ | 3 | 3 | ⋯ | 3 | 图 7.57 将 3**SAT** 归约到 **SUBSET-SUM** [逐步解释] 这部分详细描述了用于归约的数字表格的构造方法。 1. **输入和输出**: * 输入: 布尔公式 $\phi$ (有 $l$ 个变量, $k$ 个子句)。 * 输出: 一个 SUBSET-SUM 实例 $\langle S, t \rangle$。 * $S$ 和 $t$ 都是由下面表格的行定义的大数。 2. **表格结构**: * 这是一个大表格,每一行代表一个数字,每一列代表一个十进制位。 * **列的划分**: * 左边有 $l$ 列,标记为 $1, 2, \ldots, l$。这些是“**变量列**”。 * 右边有 $k$ 列,标记为 $c_1, c_2, \ldots, c_k$。这些是“**子句列**”。 * **行的划分**: * $2l$ 行,代表 $y_1, z_1, y_2, z_2, \ldots, y_l, z_l$。这些是“**变量数字**”。 * $2k$ 行,代表 $g_1, h_1, g_2, h_2, \ldots, g_k, h_k$。这些是“**填充数字**”或“**松弛数字**”。 * 最后一行是目标和 $t$。 3. **数字的构造规则**: * **变量数字 ($y_i, z_i$)**: * **变量列部分 (左侧)**: 对于数字 $y_i$ 和 $z_i$,它们在第 $i$ 列的值都是 1,在其他变量列的值都是 0。这确保了为了在第 $i$ 列凑出和为 1,必须从 $(y_i, z_i)$ 中二选一。 * **子句列部分 (右侧)**: * 对于数字 $y_i$,如果变量 $x_i$ 出现在子句 $c_j$ 中,那么 $y_i$ 在 $c_j$ 列的值为 1,否则为 0。 * 对于数字 $z_i$,如果文字 $\overline{x_i}$ 出现在子句 $c_j$ 中,那么 $z_i$ 在 $c_j$ 列的值为 1,否则为 0。 * **填充数字 ($g_j, h_j$)**: * 这些数字在所有的变量列(左侧)都为 0。 * 对于数字 $g_j$ 和 $h_j$,它们在子句列 $c_j$ 的值为 1,在其他所有子句列的值都为 0。它们是“纯净”的,只对一列有贡献。 * **目标和 ($t$)**: * **变量列部分 (左侧)**: 所有 $l$ 列的值都是 1。 * **子句列部分 (右侧)**: 所有 $k$ 列的值都是 3。 4. **表格示例的解读**: * 该表是根据示例子句 $c_1=(x_1 \vee \overline{x_2} \vee x_3), c_2=(x_2 \vee x_3 \vee \dots), c_k=(\overline{x_3} \vee \dots)$ 填充的。 * **$y_1$ 行**: 在变量列 '1' 处为 1。因为它代表 $x_1$,且 $x_1$ 出现在 $c_1$ 中,所以在子句列 '$c_1$' 处为 1。 * **$z_2$ 行**: 在变量列 '2' 处为 1。因为它代表 $\overline{x_2}$,且 $\overline{x_2}$ 出现在 $c_1$ 中,所以在子句列 '$c_1$' 处为 1。 * **$y_3$ 行**: 在变量列 '3' 处为 1。因为它代表 $x_3$,且 $x_3$ 同时出现在 $c_1$ 和 $c_2$ 中,所以它在 '$c_1$' 和 '$c_2$' 列都为 1。 * **$z_3$ 行**: 在变量列 '3' 处为 1。因为它代表 $\overline{x_3}$,且 $\overline{x_3}$ 出现在 $c_k$ 中,所以在 '$c_k$' 列为 1。 * **$g_1, h_1$ 行**: 只在子句列 '$c_1$' 处为 1。 * **$t$ 行**: 左边 $l$ 列全是 1,右边 $k$ 列全是 3。 5. **无进位设计的关键**: * 在任意一个子句列(例如 $c_j$),一个变量 $x_i$ 或 $\overline{x_i}$ 最多只出现一次(这是 3SAT 的标准形式)。因此,如果我们选择了 $l$ 个变量数字(每对二选一),在 $c_j$ 这一列上,来自这些变量数字的和最多是 3 (因为 $c_j$ 只有三个文字)。 * 再加上来自填充数字 $g_j, h_j$ 的贡献(最多是 2),这一列的总和最多是 $3+2=5$。 * 由于每一列的最大和是 5,远小于 10,所以在做加法时,**绝对不会发生进位**。这保证了每一列的求和计算都是独立的,互不干扰。变量列的计算不会影响子句列,一个子句列的计算也不会影响另一个子句列。这正是用数字的“列”来模拟独立的逻辑“子句”的关键所在。 [总结] 本段给出了 **3SAT 到 SUBSET-SUM** 归约的核心构造:一个详细的数字表格。表格中的每一行是一个大数,列代表不同的数位。归约通过以下方式编码逻辑: 1. **变量**:由一对数字 $(y_i, z_i)$ 表示,它们在专属的“变量列”上都有一个 1,强制了“二选一”。 2. **子句**: 由专属的“子句列”表示。 3. **逻辑关系**: 变量数字在子句列上的 0/1 值,反映了该变量/文字是否出现在该子句中。 4. **约束**: 目标和 $t$ 在变量列上为 1,在子句列上为 3。 5. **填充**: 引入额外的“填充数字”$(g_j, h_j)$,它们只对单个子句列有贡献,用于补足差额。 整个设计的基石是“无进位加法”,通过限制每列最大和不超过基数(这里是10),确保了各列(即各逻辑约束)之间的独立性。 [存在目的] 本段的目的是将之前抽象的证明思路,转化为一个具体的、可执行的算法。它提供了从任意 3SAT 公式 $\phi$ 生成 SUBSET-SUM 实例 $\langle S, t \rangle$ 的完整、精确的说明。这个表格是整个证明的核心,后续的正确性论证都将围绕这个表格的数学属性展开。 [直觉心智模型] 想象你在为一个由 $l$ 个部门和 $k$ 个项目组成的公司做预算。 * **$t$ (目标预算)**: 总预算。要求:每个部门经费都是1个单位;每个项目经费都是3个单位。 * **$y_i, z_i$ (决策选项)**: 每个部门 $i$ 有两个互斥的行动方案 $y_i, z_i$。 * **部门经费**: 无论选 $y_i$ 还是 $z_i$,都会消耗部门 $i$ 的1个单位经费。 * **项目经费**: 选择方案 $y_i$ (或 $z_i$) 可能会同时为某些项目贡献1个单位的经费,具体取决于方案内容(即变量是否出现在子句中)。 * **$g_j, h_j$ (备用金)**: 每个项目 $j$ 还有两笔额度为1的备用金。 * **问题**: 是否能为每个部门都选择一个行动方案,并合理使用备用金,使得最终的总开销不多不少,正好等于总预算 $t$? * **无进位**: 部门经费和项目经费是分开记账的,不会混淆。每个项目的经费也是独立核算的。这对应了无进位。 [直观想象] 你正在玩一个精密的密码锁,锁有很多行和很多列的拨轮。 * **$t$ (正确密码)**: 密码锁打开时的状态。第一组拨轮显示 "111...",第二组拨轮显示 "333..."。 * **$S$ (你的操作)**: 你不能直接拨动拨轮,你只能选择按下一些按钮。 * **$y_i, z_i$ 按钮**: 一组成对的按钮。每对中你必须按一个。按下按钮 $y_i$ 会让第一组的第 $i$ 个拨轮加1,并可能让第二组的某些拨轮也加1。 * **$g_j, h_j$ 按钮**: 另一组“微调”按钮。按下 $g_j$ 或 $h_j$ 只会让第二组的第 $j$ 个拨轮加1。 * **无进位**: 拨轮是10进制的,但设计保证了任何一列的和都不会超过5,所以没有进位。 * **问题**: 能否通过按下按钮(选择子集),让所有拨轮最终显示正确的密码 $t$? * 这个问题的解,直接对应了 3SAT 问题的解。 ## 5.4. 正确性证明 [原文] 接下来,我们展示这个构造为什么有效。我们证明 $\phi$ 是可满足的当且仅当 $S$ 的某个子集之和为 $t$。 假设 $\phi$ 是可满足的。我们构造 $S$ 的一个子集如下。如果在满足赋值中 $x_{i}$ 被赋值为 TRUE,我们选择 $y_{i}$;如果 $x_{i}$ 被赋值为 FALSE,我们选择 $z_{i}$。如果我们把目前选择的加起来,我们会在前 $l$ 位得到一个 1,因为我们为每个 $i$ 选择了一个 $y_{i}$ 或 $z_{i}$。此外,后 $k$ 位中的每一位都是 1 到 3 之间的数字,因为每个子句都得到满足,因此包含 1 到 3 个真文字。我们另外选择足够多的 $g$ 和 $h$ 数字,使后 $k$ 位中的每一位都达到 3,从而达到目标。 假设 $S$ 的一个子集之和为 $t$。我们通过几次观察来构造 $\phi$ 的一个满足赋值。首先,$S$ 成员中的所有数字都是 0 或 1。此外,描述 $S$ 的表格中的每一列最多包含五个 1。因此,当 $S$ 的一个子集相加时,绝不会发生进位到下一列。为了在前 $l$ 列中得到一个 1,该子集必须为每个 $i$ 包含 $y_{i}$ 或 $z_{i}$,但不能两者都包含。 现在我们进行满足赋值。如果子集包含 $y_{i}$,我们将 $x_{i}$ 赋值为 TRUE;否则,我们将其赋值为 FALSE。这个赋值必须满足 $\phi$,因为在最后 $k$ 列中的每一列,和总是 3。在列 $c_{j}$ 中,最多 2 可以来自 $g_{j}$ 和 $h_{j}$,因此该列中至少有 1 必须来自子集中的某个 $y_{i}$ 或 $z_{i}$。如果是 $y_{i}$,则 $x_{i}$ 出现在 $c_{j}$ 中并被赋值为真,因此 $c_{j}$ 得到满足。如果是 $z_{i}$,则 $\overline{x_{i}}$ 出现在 $c_{j}$ 中并且 $x_{i}$ 被赋值为假,因此 $c_{j}$ 得到满足。因此,$\phi$ 得到满足。 最后,我们必须确保归约可以在多项式时间内完成。该表格的大小大约为 $(k+l)^{2}$,并且对于任何 $\phi$,每个条目都可以轻松计算。因此,总时间是 $O\left(n^{2}\right)$ 的简单阶段。 [逐步解释] 这部分对 **SUBSET-SUM** 归约的正确性进行了双向证明。 **第一部分:证明 $\phi$ 可满足 $\Rightarrow$ 存在和为 $t$ 的子集** 1. **“假设 $\phi$ 是可满足的。”**: 我们从一个已知的满足赋值开始。 2. **构造子集 - 第一步 (变量数字)**: * 根据赋值来选择变量数字: * 如果 $x_i$ 为真,选择 $y_i$ 放入子集。 * 如果 $x_i$ 为假,选择 $z_i$ 放入子集。 * 这一步我们选了 $l$ 个数字。 3. **部分和的分析**: * **变量列 (左侧)**: 对于每一列 $i$,我们都从 $(y_i, z_i)$ 中选了一个,且只选了一个。这两个数字在第 $i$ 列都是 1。因此,我们选出的 $l$ 个数字在每一列变量列上的和都恰好是 1。这与目标 $t$ 的左半部分完全匹配。 * **子句列 (右侧)**: 对于每一列 $c_j$,其和是多少?这个和等于我们选出的 $l$ 个变量数字中,在 $c_j$ 列为 1 的个数。这等价于在子句 $c_j$ 中,被赋值为真的文字的数量。因为我们假设 $\phi$ 是可满足的,所以每个子句都至少有一个真文字。因此,对于每一列 $c_j$,目前来自变量数字的和是一个在 1 到 3 之间的整数。 4. **构造子集 - 第二步 (填充数字)**: * 我们的目标是让每个子句列的和都达到 3。 * 对于每个子句列 $c_j$: * 如果来自变量数字的和是 1,我们就需要再补 2。我们把 $g_j$ 和 $h_j$ 都选入子集(它们各贡献1)。 * 如果来自变量数字的和是 2,我们就需要再补 1。我们只选择 $g_j$(或 $h_j$)放入子集。 * 如果来自变量数字的和是 3,我们什么都不用补。我们不选择 $g_j$ 和 $h_j$。 5. **最终验证**: * 我们构造的子集包含了 $l$ 个变量数字和一些填充数字。 * 将子集中的所有数字相加。由于无进位,我们可以按列检查: * 左边 $l$ 个变量列,每一列的和都是 1。 * 右边 $k$ 个子句列,每一列的和都被我们精确地补到了 3。 * 这个总和与目标和 $t$ 完全相同。因此,我们成功找到了一个和为 $t$ 的子集。 **第二部分:证明 存在和为 $t$ 的子集 $\Rightarrow \phi$ 可满足** 1. **“假设 $S$ 的一个子集之和为 $t$。”**: 我们从一个已知的解(一个和为 $t$ 的子集)开始。 2. **“首先...绝不会发生进位到下一列。”**: 这是整个反向证明的基石。因为每列的和最多是 5 (3个来自变量,2个来自填充),所以求和时不同列之间是完全独立的。我们可以像解方程组一样,独立地看每一列。 3. **分析变量列 (左侧)**: * 目标 $t$ 在变量列 $i$ 的值是 1。 * 在整个集合 $S$ 中,只有 $y_i$ 和 $z_i$ 在这一列有非零值 (都是1)。 * 为了让第 $i$ 列的和为 1,我们必须且只能从 $\{y_i, z_i\}$ 中选择一个放入子集。不能都不选(和为0),也不能都选(和为2)。 * 这对所有 $l$ 个变量列都成立。因此,解子集必须包含 $l$ 个变量数字,每对 $(y_i, z_i)$ 中恰好一个。 4. **构造赋值**: * 基于上面的观察,我们这样定义赋值: * 如果解子集中包含 $y_i$,则令 $x_i = $ 真。 * 如果解子集中包含 $z_i$,则令 $x_i = $ 假。 * 这是一个明确、无矛盾的赋值。 5. **验证赋值的满足性**: * 我们现在需要证明这个赋值能满足所有子句。 * 分析任意一个子句列 $c_j$。我们知道解子集在这一列的和必须是 3。 * 这个和来自两部分:来自所选的 $l$ 个变量数字的贡献,和来自填充数字 $g_j, h_j$ 的贡献。 * 填充数字 $g_j, h_j$ 在 $c_j$ 列最多只能贡献 2 (如果两个都选)。 * 因此,为了凑够 3,来自**变量数字**的贡献必须**至少是 1**。 * 来自变量数字在 $c_j$ 列的贡献是什么?就是我们根据赋值选中的那些 $y_i$ 或 $z_i$ 中,在 $c_j$ 列为 1 的个数。 * 这个贡献至少是 1,意味着至少有一个被选中的变量数字,在 $c_j$ 列为 1。 * 如果这个数字是 $y_i$,意味着我们选了 $y_i$ (即 $x_i=$ 真),并且 $y_i$ 在 $c_j$ 列为 1 (即 $x_i$ 出现在 $c_j$ 中)。所以 $c_j$ 被满足。 * 如果这个数字是 $z_i$,意味着我们选了 $z_i$ (即 $x_i=$ 假),并且 $z_i$ 在 $c_j$ 列为 1 (即 $\overline{x_i}$ 出现在 $c_j$ 中)。所以 $c_j$ 也被满足。 * 既然对任意子句 $c_j$ 都成立,那么整个公式 $\phi$ 都被满足。 6. **多项式时间分析**: * 构造表格需要多少时间?表格有 $2l+2k+1$ 行, $l+k$ 列。大小是 $O((l+k)^2)$。 * 每个格子的数字是 0 或 1,计算很简单。 * 将这些 0/1 序列转换为十进制大数,所需的时间也与数字的位数(即 $l+k$)成多项式关系。 * 公式大小 $n \approx l+k$,所以构造时间是 $O(n^2)$ 级别,是多项式时间的。 [总结] 本段完美地完成了 **SUBSET-SUM** 归约的正确性证明。 * **正向证明**展示了如何从一个满足赋值出发,通过“按值选变量,按需选填充”的策略,精确地构造出一个和为 $t$ 的数字子集。 * **反向证明**利用了“无进位”这一关键特性,首先证明了任何解子集都必须对每对变量数字作“二选一”,从而建立了一个从解到赋值的唯一映射。然后通过分析子句列的和,证明了这个赋值必须满足所有子句。 * 最后,分析了构造过程的时间复杂度,确认其为多项式级别。至此,**SUBSET-SUM** 是 **NP-完全**的结论被牢固确立。 [存在目的] 本段是 **SUBSET-SUM** 归约的逻辑核心。它用严谨的数学推导,验证了上一节中精巧的数字构造确实达到了预期的目的。它展示了算术运算(求和)是如何在特定的约束(无进位)下,完美地模拟了布尔逻辑运算。这是 **NP-完全**性理论中一个极具代表性和启发性的证明。 [直觉心智模型] 回到预算问题: * **正向证明**: 如果你有一个可行的公司运营方案(满足赋值),那么你就能制定出一份完美的预算执行单。你先根据方案选择必须执行的部门行动(选 $y_i, z_i$),然后发现每个项目都至少有了一笔启动资金。最后你再从备用金里拨款,把每个项目的经费都补足到3个单位。最终总开销正好等于总预算。 * **反向证明**: 你拿到了一份据说是完美的预算执行单(解子集)。你检查后发现:1. 每个部门的经费正好是1,这说明每个部门都恰好执行了一个行动方案。你据此可以反推出公司的运营方案。2. 你发现每个项目的经费都是3,而备用金最多只能提供2,所以每个项目一开始就必须从部门的行动方案里至少获得1个单位的经费。这说明你反推出的这个运营方案,保证了每个项目都能启动,是可行的。 [直观想象] 回到密码锁问题: * **正向证明**: 如果你知道谜题的正确答案(满足赋值),你就可以按答案去按动对应的 $y_i, z_i$ 按钮。然后你观察第二组拨轮的状态,发现每个拨轮显示的数字都是1、2或3。你再按动相应的微调按钮 $g_j, h_j$ 一次或两次,就能把所有拨轮都调到3。此时,你看整个密码锁,它显示的就是正确的密码 $t$。 * **反向证明**: 你发现了一组能打开锁的按钮组合(解子集)。你分析后发现:1. 要让第一组拨轮显示 "111...",你必须在每对 $(y_i, z_i)$ 按钮中只按一个。这给了你一个谜题的答案。2. 你又发现,要让第二组的第 $j$ 个拨轮显示3,光靠微调按钮(最多加2)是不够的,必须有某个你按下的 $y_i/z_i$ 按钮为它贡献了至少1。这说明你的答案让谜题的第 $j$ 个逻辑约束被满足了。这对所有逻辑约束都成立,所以你的答案是正确的。 # 6. 练习题解析 ## 6.1. 练习 7.1 [原文] 7.1 回答每个部分“真”或“假”。 a. $2 n=O(n)$。 **A**d. $n \log n=O\left(n^{2}\right)$。 b. $n^{2}=O(n)$。 e. $3^{n}=2^{O(n)}$。 **A**c. $n^{2}=O\left(n \log ^{2} n\right)$。 f. $2^{2^{n}}=O\left(2^{2^{n}}\right)$。 [逐步解释] 这个练习考察对大O符号 (Big-O notation) 的基本理解。大O符号描述了函数增长的**上界**。$f(n) = O(g(n))$ 意味着函数 $f(n)$ 的增长速度不快于函数 $g(n)$(在某个常数因子下)。 * **a. $2n = O(n)$**: **真**。 * **解释**: $2n$ 和 $n$ 是线性关系。根据大O定义,存在常数 $c=3$ 和 $n_0=1$,使得对于所有 $n \ge n_0$,都有 $2n \le c \cdot n$。常数因子在O表示法中被忽略。 * **b. $n^2 = O(n)$**: **假**。 * **解释**: $n^2$ (二次方) 的增长速度**快于** $n$ (线性)。不存在任何常数 $c$,使得当 $n$ 足够大时,$n^2 \le c \cdot n$ 成立。因为该不等式化简为 $n \le c$,而 $n$ 是可以无限增长的。 * **c. $n^2 = O(n \log^2 n)$**: **假**。 * **解释**: $n^2$ 的增长速度**快于** $n \log^2 n$。比较 $n^2$ 和 $n \log^2 n$,可以消去一个 $n$,变成比较 $n$ 和 $\log^2 n$。$n$ 的增长速度远快于 $\log^2 n$。 * **d. $n \log n = O(n^2)$**: **真**。 * **解释**: $n \log n$ 的增长速度**慢于** $n^2$。比较 $n \log n$ 和 $n^2$,消去 $n$ 后变成比较 $\log n$ 和 $n$。$n$ 的增长速度远快于 $\log n$。因此 $n \log n$ 被 $n^2$ "压住"了。 * **e. $3^n = 2^{O(n)}$**: **真**。 * **解释**: 这是一个关于指数函数底数变换的问题。$3^n = (2^{\log_2 3})^n = 2^{n \log_2 3}$。因为 $\log_2 3$ 是一个常数 (大约 1.58),所以 $n \log_2 3$ 是 $n$ 的线性函数,即 $n \log_2 3 = O(n)$。因此,整个表达式可以写成 $2^{O(n)}$。 * **f. $2^{2^n} = O(2^{2^n})$**: **真**。 * **解释**: 任何函数都是其自身的上界(当常数 $c \ge 1$ 时)。$f(n) = O(f(n))$ 总是成立的。这在考察大O定义的边界情况。 ## 6.2. 练习 7.2 [原文] 7.2 回答每个部分“真”或“假”。 a. $n=o(2 n)$。 ${ }^{\text {A }}$d. $1=o(n)$。 b. $2 n=o\left(n^{2}\right)$。 e. $n=o(\log n)$。 **A**c. $2^{n}=o\left(3^{n}\right)$。 f. $1=o(1 / n)$。 [逐步解释] 这个练习考察对小o符号 (little-o notation) 的理解。小o符号描述了函数增长的**严格上界**。$f(n) = o(g(n))$ 意味着函数 $f(n)$ 的增长速度**远慢于**函数 $g(n)$。形式上,$\lim_{n \to \infty} \frac{f(n)}{g(n)} = 0$。 * **a. $n=o(2 n)$**: **假**。 * **解释**: $n$ 和 $2n$ 的增长速度是同阶的(线性)。它们的比值 $\frac{n}{2n} = \frac{1}{2}$,极限不为 0。 * **b. $2n=o(n^2)$**: **真**。 * **解释**: 线性增长远慢于二次方增长。它们的比值 $\frac{2n}{n^2} = \frac{2}{n}$,当 $n \to \infty$ 时,极限为 0。 * **c. $2^n=o(3^n)$**: **真**。 * **解释**: 指数函数,底数越大增长越快。它们的比值 $\frac{2^n}{3^n} = (\frac{2}{3})^n$。因为 $\frac{2}{3} < 1$,当 $n \to \infty$ 时,极限为 0。 * **d. $1=o(n)$**: **真**。 * **解释**: 常数增长远慢于线性增长。它们的比值 $\frac{1}{n}$,当 $n \to \infty$ 时,极限为 0。 * **e. $n=o(\log n)$**: **假**。 * **解释**: 线性增长**快于**对数增长。它们的比值 $\frac{n}{\log n}$,当 $n \to \infty$ 时,极限为 $\infty$。应该是 $\log n = o(n)$。 * **f. $1=o(1/n)$**: **假**。 * **解释**: 当 $n \to \infty$ 时,$1/n$ 趋近于 0。常数 1 比一个趋近于 0 的函数增长得**快得多**。它们的比值 $\frac{1}{1/n} = n$,极限为 $\infty$。 ## 6.3. 练习 7.3 - 7.12 [逐步解释] * **7.3 互质判断**: 要求使用欧几里得算法(辗转相除法)来计算两对数的最大公约数 (GCD)。如果 GCD 为 1,则两数互质。这是一个 **P** 类问题。 * **7.4 CFG 动态规划**: 要求手动执行 CYK 算法(或类似的基于动态规划的上下文无关文法识别算法),填写一个表格来判断字符串 "baba" 是否能被给定的文法 $G$ 生成。这也是一个 **P** 类问题。 * **7.5 公式可满足性**: 询问公式 $(x \vee y) \wedge(x \vee \bar{y}) \wedge(\bar{x} \vee y) \wedge(\bar{x} \vee \bar{y})$ 是否可满足。可以通过观察发现: * $(x \vee y) \wedge(x \vee \bar{y})$ 等价于 $x$。 * $(\bar{x} \vee y) \wedge(\bar{x} \vee \bar{y})$ 等价于 $\bar{x}$。 * 所以整个公式等价于 $x \wedge \bar{x}$,这永远为假。因此公式**不可满足**。 * **7.6 P 的封闭性**: 要求证明 **P** 类在并集、连接和补集运算下是封闭的。 * **并集**: 运行两个多项式时间算法,如果任何一个接受,则接受。总时间是多项式。 * **连接**: 假设字符串 $w$ 可以分割成 $w=uv$,其中 $u$ 在语言 A, $v$ 在语言 B。可以遍历所有可能的分割点,对每个分割点运行两个多项式算法。分割点有 $n+1$ 个,总时间是多项式。 * **补集**: 运行原来的多项式时间算法,如果它接受则拒绝,如果它拒绝则接受。时间不变。 * **7.7 NP 的封闭性**: 要求证明 **NP** 在并集和连接下是封闭的。 * **并集**: 非确定性地猜测输入 $w$ 属于哪个语言,然后使用该语言的验证器来验证。 * **连接**: 非确定性地猜测 $w$ 的分割点,然后非确定性地为两部分猜测证书,并同时验证。 * **7.8 CONNECTED in P**: 要求分析图的连通性算法(如广度优先搜索 BFS 或深度优先搜索 DFS),证明它在多项式时间内运行,因此 **CONNECTED** 问题属于 **P** 类。BFS/DFS 的时间复杂度是 $O(V+E)$,其中 V 是节点数,E 是边数,这是多项式的。 * **7.9 TRIANGLE in P**: 要求证明在图中寻找一个三角形(3-团)是 **P** 类问题。可以通过遍历所有三元组节点 $\{i, j, k\}$,检查它们之间是否两两都有边。节点数为 $n$ 时,有 $O(n^3)$ 个三元组,这是一个多项式时间算法。 * **7.10 $ALL_{DFA}$ in P**: $ALL_{DFA} = \{\langle A \rangle \mid A \text{ is a DFA and } L(A) = \Sigma^*\}$。要判断一个 DFA 是否接受所有字符串,等价于判断其补语言是否为空。构造 DFA $A$ 的补 DFA(接受状态变非接受,反之亦然)是容易的。然后判断这个补 DFA 的语言是否为空,只需检查从起始状态是否能到达任何一个接受状态。这可以用 BFS/DFS 在多项式时间内完成。 * **7.11 算法时间复杂性分析**: * **a. $EQ_{DFA} \in P$**: 判断两个 DFA $A$ 和 $B$ 是否等价。可以构造一个新的 DFA $C$,它接受的语言是 $(L(A) \cap \overline{L(B)}) \cup (\overline{L(A)} \cap L(B))$(对称差)。这可以通过标准的DFA乘积和补运算构造出来。然后判断 $L(C)$ 是否为空即可。所有步骤都是多项式时间的。 * **b. 星封闭语言**: 判断 DFA $A$ 的语言是否满足 $L(A) = (L(A))^*$。这等价于判断 $L(A)$ 是否等于 $L(A^*)$。我们可以为 $L(A)$ 构造一个识别 $L(A)^*$ 的 NFA(通过在 $A$ 的接受状态到开始状态加 $\epsilon$ 边等方法),然后将其确定化为 DFA $B$。最后判断 DFA $A$ 和 DFA $B$ 是否等价,这又回到了 (a) 中的 $EQ_{DFA}$ 问题。 * **7.12 ISO in NP**: $ISO = \{\langle G, H \rangle \mid G, H \text{ 是同构图}\}$。要求证明图同构问题属于 **NP**。给定一个声称是同构的节点映射 $f: V_G \to V_H$ 作为证书。我们可以在多项式时间内验证它:1. 检查 $f$是否是一个双射(一一对应)。2. 检查对于 $G$ 中的任意两个节点 $u, v$,边 $(u,v)$ 存在当且仅当边 $(f(u), f(v))$ 在 $H$ 中存在。这个验证过程是多项式时间的,因此 $ISO \in \mathrm{NP}$。(注意:$ISO$ 是否在P或NP-complete中,是著名的未解难题。) # 7. 行间公式索引 1. $$

\phi=\left(a_{1} \vee b_{1} \vee c_{1}\right) \wedge\left(a_{2} \vee b_{2} \vee c_{2}\right) \wedge \cdots \wedge\left(a_{k} \vee b_{k} \vee c_{k}\right),

$$ **解释**:一个泛化的 3-CNF 布尔公式 $\phi$ 的结构,由 $k$ 个子句通过逻辑与连接而成。 2. $$

s, u_{1}, u_{2}, \ldots, u_{k}, t,

$$ **解释**:一条通过有向图 $G$ 的哈密顿路径 $P$ 的节点序列。 3. $$

s^{\text {out }}, u_{1}^{\text {in }}, u_{1}^{\text {mid }}, u_{1}^{\text {out }}, u_{2}^{\text {in }}, u_{2}^{\text {mid }}, u_{2}^{\text {out }}, \ldots, t^{\text {in }} .

$$ **解释**:在无向图 $G'$ 中,与有向图 $G$ 的哈密顿路径 $P$ 相对应的哈密顿路径 $P'$ 的节点序列。 4. $$

y_{1}, z_{1}, y_{2}, z_{2}, \ldots, y_{l}, z_{l} \quad \text { 和 } \quad g_{1}, h_{1}, g_{2}, h_{2}, \ldots, g_{k}, h_{k}

$$ **解释**:在 **3SAT** 到 **SUBSET-SUM** 的归约中,所构造的数字集合 $S$ 的元素构成,分为变量数字和填充数字。 5. $$

\left(x_{1} \vee \overline{x_{2}} \vee x_{3}\right) \wedge\left(x_{2} \vee x_{3} \vee \cdots\right) \wedge \cdots \wedge\left(\overline{x_{3}} \vee \cdots \vee \cdots\right) .

$$ **解释**:一个具体的 3-CNF 公式例子,用于说明 **SUBSET-SUM** 归约中数字表格的填充方法。 6. $$

\begin{aligned}

& S \rightarrow R T \\

& R \rightarrow T R \mid \mathrm{a} \\

& T \rightarrow T R \mid \mathrm{b}

\end{aligned}

$$ **解释**:练习题 7.4 中给出的一个上下文无关文法 (CFG),用于识别特定语言。 7. $$

(x \vee y) \wedge(x \vee \bar{y}) \wedge(\bar{x} \vee y) \wedge(\bar{x} \vee \bar{y})

$$ **解释**:练习题 7.5 中给出的一个布尔公式,要求判断其是否可满足。 [[END_OF_RESPONSE]]所有解释内容已全部输出完毕。``` $$