1. 讲义 11B:复杂性复习 - 解答

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

11. 讲义 11B:复杂性复习 - 解答

📜 [原文1]

讲义 11B:复杂性复习 - 解答 <br> William Pires

📖 [逐步解释]

这是讲义的标题和作者信息。“讲义 11B”表明这是系列讲义中的第11部分的B部分,通常A部分是问题,B部分是解答。“复杂性复习 - 解答”明确了这份文档的核心内容,即关于计算复杂性理论(Computational Complexity Theory)的复习题的官方解答。“William Pires”是这份讲义的作者。计算复杂性理论是理论计算机科学的核心分支,它研究计算问题根据其内在难度(需要多少计算资源)进行分类。

💡 [数值示例]

无。

⚠️ [易错点]

无。

📝 [总结]

本部分是文档的元信息,点明了主题(复杂性理论习题解答)、来源(讲义11B)和作者。

🎯 [存在目的]

标题和作者部分的存在是为了让学生和读者能够快速识别文档内容、出处和作者,便于归档和查阅。

🧠 [直觉心智模型]

可以将这份文档看作是一本练习册的答案页。标题就像答案页的页眉,告诉你这是“第11章B节:复杂性”这部分的答案。

💭 [直观想象]

想象你刚做完一套关于“计算复杂性”的测验题,现在老师把标准答案发下来了,你拿到的这份文档就是那份标准答案,文档的开头清楚地写着“复杂性复习 - 解答”。

22. 练习 1(判断题)

2.1. 问题 1

📜 [原文2]

  1. 所有 $n \cdot \log (n), n^{100}+3 n^{2}, n^{0.001 n}, 2^{\sqrt{n}}$ 都是多项式的。

答案:$n \cdot \log (n), n^{100}+3 n^{2}$ 是多项式的,$n^{0.001 n}, 2^{\sqrt{n}}$ 不是。

📖 [逐步解释]

这个问题要求我们判断给出的四个函数增长率是否属于多项式级别。在计算复杂性理论中,一个函数 $f(n)$ 被认为是多项式的,如果它被一个多项式函数所界定,即存在一个常数 $c > 0$ 和一个常数 $k$,使得对于所有足够大的 $n$,$f(n) \le c \cdot n^k$。这个界定通常使用大O符号表示为 $f(n) = O(n^k)$。

  1. $n \cdot \log(n)$: 这个函数增长得比 $n$ 快,但比 $n^2$ 慢。我们可以找到一个常数 $k=2$,因为对于足够大的 $n$,$n \cdot \log(n) \le n^2$ 总是成立的。所以 $n \cdot \log(n)$ 的增长率是多项式级别的(严格来说是准多项式时间,但在P类的上下文中,它被认为是高效的,并且被多项式所界定)。
  2. $n^{100}+3n^2$: 这是一个真正的多项式函数。它的最高次项是 $n^{100}$。根据大O表示法的规则,我们只关心最高次项,所以这个函数的增长率是 $O(n^{100})$。因为它的增长率可以被 $n^k$(这里 $k=100$)形式的函数界定,所以它是多项式的。
  3. $n^{0.001n}$: 这个函数的指数部分包含了变量 $n$。这种形式的函数,如 $n^n$,被称为超多项式指数级的。它的增长速度远远超过任何多项式函数 $n^k$。随着 $n$ 的增大,$0.001n$ 这一项会变得非常大,使得整个表达式的增长是指数性的。
  4. $2^{\sqrt{n}}$: 这个函数是一个指数函数,其底数为常数2,指数为 $n$ 的函数 $\sqrt{n}$。任何形如 $a^{f(n)}$(其中 $a>1$ 且 $f(n)$ 是一个随 $n$ 增长的函数)的函数,如果其指数部分不是对数级的,那么它通常是指数级的。$2^{\sqrt{n}}$ 的增长速度比任何多项式 $n^k$ 都要快。这被称为准指数时间

因此,答案是正确的。前两者被多项式函数所界定,而后两者不是。

∑ [公式拆解]
  • 多项式函数:一个函数 $f(n)$ 是多项式的,如果它可以写成 $f(n) = a_k n^k + a_{k-1} n^{k-1} + \dots + a_1 n + a_0$ 的形式,其中 $k$ 是一个非负整数(次数),$a_i$ 是常数。在复杂性理论中,如果一个函数的运行时间 $T(n)$ 满足 $T(n) = O(n^k)$ 对于某个常数 $k$,我们就说这个算法是多项式时间算法。
  • $n \cdot \log(n)$: 属于拟多项式准多项式 (quasi-polynomial)。它比任何线性函数 $O(n)$ 增长快,但比任何二次函数 $O(n^{1+\epsilon})$ (对于任意 $\epsilon > 0$) 增长慢。由于存在 $k=2$ 使得 $n \log(n) \le n^2$(对于足够大的 $n$),它被多项式 $n^2$ 所上界,因此可归为多项式有界。
  • $n^{100}+3n^2$: 这是一个次数为100的多项式。其复杂度为 $O(n^{100})$。
  • $n^{0.001n}$: 这是一个超多项式函数。可以重写为 $(e^{\ln n})^{0.001n} = e^{0.001n \ln n}$。它的增长速度远超任何多项式
  • $2^{\sqrt{n}}$: 这是一个指数函数。它的增长速度也远超任何多项式。为了证明这一点,我们可以比较 $\log(2^{\sqrt{n}}) = \sqrt{n}$ 和 $\log(n^k) = k \log n$。对于任何常数 $k$,当 $n$ 足够大时,$\sqrt{n}$ 总是会超过 $k \log n$。
💡 [数值示例]
  • 示例 1: 设 $n=1,000,000 = 10^6$。
  • $n \cdot \log_{10}(n) = 10^6 \cdot \log_{10}(10^6) = 10^6 \cdot 6 = 6,000,000$。
  • $n^2 = (10^6)^2 = 10^{12}$。显然 $6 \cdot 10^6 \ll 10^{12}$,符合多项式界定。
  • $n^{100}$ 已经是 $(10^6)^{100} = 10^{600}$,这是一个巨大的数,但仍然是多项式形式。
  • $n^{0.001n} = (10^6)^{0.001 \cdot 10^6} = (10^6)^{1000} = 10^{6000}$。这个数远远大于 $10^{600}$。
  • $2^{\sqrt{n}} = 2^{\sqrt{10^6}} = 2^{1000} \approx (10^{0.301})^{1000} = 10^{301}$。这个数也极其巨大,且增长模式非多项式
  • 示例 2: 设 $k=100$。我们比较 $n^k$ 和 $2^{\sqrt{n}}$。
  • 当 $n=40000$ 时,$n^k = 40000^{100} = (4 \cdot 10^4)^{100} = 4^{100} \cdot 10^{400} \approx (10^{0.6})^{100} \cdot 10^{400} = 10^{60} \cdot 10^{400} = 10^{460}$。
  • 而 $2^{\sqrt{n}} = 2^{\sqrt{40000}} = 2^{200} \approx (10^{0.301})^{200} = 10^{60.2}$。此时 $n^k$ 更大。
  • 但我们看增长趋势。当 $n$ 变得更大,例如 $n=10^{10}$ 时,$\sqrt{n}=10^5$。$2^{\sqrt{n}} = 2^{100000} \approx 10^{30100}$。而 $n^{100} = (10^{10})^{100} = 10^{1000}$。显然指数函数已经远远超过了多项式函数。
⚠️ [易错点]
  1. 误区: 将 $n \cdot \log(n)$ 误认为非多项式。虽然它不是一个严格的多项式,但在复杂性分类中,任何被 $O(n^k)$ 界定的函数都被认为是多-时间可解的,因此 $n \cdot \log(n)$ 属于这一类。
  2. 误区: 看到 $n^{100}$ 中的指数100非常大,就误以为它不是“高效”的。虽然在实践中可能很慢,但从理论复杂性的角度看,只要指数是常数,它就是多项式的。多项式指数之间的鸿沟是理论上最重要的区别。
  3. 关键区别: 判断的关键在于,指数部分是否为常数(如 $n^{100}$)或者是一个仅依赖于 $\log n$ 的函数,还是一个随 $n$ 线性或更高次增长的函数(如 $n^{0.001n}$ 或 $2^{\sqrt{n}}$)。
📝 [总结]

该问题考察了对多项式时间复杂度基本定义的理解。核心是区分多项式增长(如 $n^c$)和指数增长(如 $c^n$ 或 $n^n$)。$n \cdot \log(n)$ 和 $n^{100}+3n^2$ 的增长率被多项式函数所限制,而 $n^{0.001n}$ 和 $2^{\sqrt{n}}$ 的增长速度超过了任何多项式函数。

🎯 [存在目的]

这个问题的目的是为了检验学生是否掌握了复杂性理论中最基本的概念之一:区分多项式与非多项式(主要是指数)增长函数。这是理解P类与NP类等后续概念的基础。

🧠 [直觉心智模型]
  1. 多项式增长就像开车:你可以开得很快(比如 $n^{100}$ 就像一辆超级跑车),但你的速度终究是一个固定的马力(指数是常数)。
  2. 指数增长就像火箭:它的速度本身在不断地、爆炸性地增加(指数部分依赖于 $n$)。刚开始可能比跑车慢,但很快就会将其远远甩在身后。
💭 [直观想象]

想象两条曲线在坐标系上。一条是 $y=x^2$(多项式),它是一条向上弯曲的抛物线。另一条是 $y=2^x$(指数),它开始时非常平缓,但在某个点之后会急剧、近乎垂直地上升。$n^{0.001n}$ 和 $2^{\sqrt{n}}$ 就属于后一类,它们的增长最终会比任何多项式曲线都更“陡峭”。

2.2. 问题 2

📜 [原文3]

  1. 如果您为一个语言 $L$ 展示了一个验证器 $V(x, c)$,其中 $V$ 运行时间是 $|x|+|c|$ 的多项式,那么 $L$ 一定在 NP 中。

答案:错误。要使 $L$ 在 NP 中,您需要一个验证器,其运行时间是 $|x|$ 的多项式¹。如果您允许 $c$ 的长度是 $|x|$ 的指数级,并且您允许 $V$ 运行时间是 $|x|+|c|$ 的多项式,那么您实际上已经允许 $V$ 运行时间是 $|x|$ 的指数级。

📖 [逐步解释]

这个问题考察的是对 NP 类 定义的精确理解。NP (Nondeterministic Polynomial time) 的核心定义之一是基于验证器的。

一个语言 $L$ 属于 NP,如果存在一个确定性图灵机(即验证器) $V$,它满足两个条件:

  1. 高效验证:$V$ 的运行时间必须是输入字符串 $x$ 长度的多项式,即 $O(|x|^k)$,其中 $k$ 是一个常数
  2. 完备性与可靠性
    • 如果 $x \in L$,那么存在一个“证据”或“证书” $c$,使得 $V(x, c)$ 接受。
    • 如果 $x \notin L$,那么对于所有的证书 $c$,$V(x, c)$ 都拒绝。

从条件1可以推断出,证书 $c$ 的长度也必须是 $|x|$ 的多项式。为什么呢?因为如果 $c$ 的长度是 $|x|$ 的指数级,一个运行时间为 $|x|$ 多项式的验证器甚至没有足够的时间来完整地读取证书 $c$。

现在我们来看题目中的陈述:验证器 $V$ 的运行时间是 $|x|+|c|$ 的多项式。这看起来似乎是高效的,但问题在于它没有限制证书 $c$ 的长度。

错误之处:如果我们可以选择一个长度是 $|x|$ 指数级的证书 $c$(例如, $|c| = 2^{|x|}$),那么运行时间是 $|x|+|c|$ 的多项式,比如 $O((|x|+|c|)^2)$, 将会变成 $O((|x|+2^{|x|})^2)$。这个时间是关于 $|x|$ 的指数级,而不是多项式级。

这意味着,通过使用一个非常长的证书,我们给了验证器指数级的计算时间。这违反了 NP 定义中“多项式时间验证”的核心要求。这样的语言可能属于 NEXP (Nondeterministic Exponential Time),但不一定在 NP 中。

∑ [公式拆解]
  • NP 的验证器定义: 语言 $L \in \mathrm{NP}$ 当且仅当存在一个多项式时间的验证器 $V$ 和一个多项式 $p$,使得对于任何字符串 $x$:

$x \in L \iff \exists c$ 使得 $|c| \le p(|x|)$ 且 $V(x, c)$ 在 $O(|x|^k)$ 时间内接受。

  • $|x|$: 输入字符串 $x$ 的长度。
  • $|c|$: 证书 $c$ 的长度。
  • $V(x,c)$: 验证器,输入为 $x$ 和证书 $c$。
  • $O(|x|^k)$: 验证器 $V$ 的运行时间必须是 $|x|$ 的多项式
  • $|c| \le p(|x|)$: 证书 $c$ 的长度也必须是 $|x|$ 的多项式
  • 题目中的情况:
  • 运行时间 $T(V) = O((|x|+|c|)^k)$。
  • 对 $|c|$ 没有明确的多项式界定。
  • 反例: 假设我们有一个问题,它的证书长度 $|c|$ 是 $|x|$ 的指数级,比如 $|c| = 2^{|x|}$。
  • 那么验证器的运行时间 $T(V) = O((|x| + 2^{|x|})^k)$。当 $|x|$ 很大时,$2^{|x|}$ 占主导地位,所以 $T(V) \approx O((2^{|x|})^k) = O(2^{k|x|})$。这是一个关于 $|x|$ 的指数时间,而不是多项式时间
💡 [数值示例]
  • 示例 1 (符合NP定义): 假设验证器运行时间是 $O(|x|^2)$,证书长度 $|c|$ 是 $O(|x|^3)$。
  • 设 $|x|=10$。那么验证时间是 $10^2=100$ 的量级。证书长度是 $10^3=1000$ 的量级。验证器有足够的时间处理证书,并且总时间是输入 $|x|$ 的多项式
  • 比如对于哈密顿路径问题,输入图 $G$ 的大小是 $|x|$,证书 $c$ 可以是点的序列,长度为 $O(|x|)$。验证器检查这个序列是否是 $G$ 中的一条有效路径并访问了所有点,时间是 $|x|$ 的多项式
  • 示例 2 (题设的漏洞): 假设验证器运行时间是 $O(|x|+|c|)$。
  • 设 $|x|=10$。
  • 假设我们允许证书长度是指数级的,比如 $|c|=2^{|x|} = 2^{10} = 1024$。
  • 那么验证器的运行时间就是 $O(10 + 1024) = O(1034)$。
  • 现在设 $|x|=20$。
  • 证书长度 $|c|=2^{20} \approx 1,000,000$。
  • 验证器的运行时间就是 $O(20 + 1,000,000)$,大约是 $10^6$ 量级。
  • 看起来运行时间是随着 $|c|$ 线性增长,但 $|c|$ 本身是随 $|x|$ 指数增长的。所以总的运行时间 $T(|x|) \approx O(2^{|x|})$,这是指数级的。
⚠️ [易错点]
  1. 混淆验证时间和证书长度: 学生容易忽略对证书长度的隐藏限制。NP 的定义要求验证过程整体上相对于原始输入 $|x|$ 是高效的,这不仅限制了计算步骤,也间接限制了可用于计算的“原材料”(即证书)的数量。
  2. 表面上的多项式: “$|x|+|c|$ 的多项式”这个表述具有欺骗性。它本身是一个多项式,但其变量依赖于一个可能非多项式大小的项 $c$,导致整体相对于 $x$ 是非多项式的。
📝 [总结]

这个判断题是错误的。NP 的核心要求是验证器相对于输入 $|x|$ 的大小是多项式时间的。这隐含地要求了证书 $|c|$ 的大小也必须是 $|x|$ 的多项式。题目中的条件允许证书 $c$ 的长度是指数级的,从而使得总验证时间相对于 $|x|$ 变成指数级,这不符合 NP 的定义。

🎯 [存在目的]

此题旨在深化学生对 NP 形式化定义的理解,特别是对验证时间和证书长度的双重多项式约束的认识。它强调了复杂性分析中,“相对于谁”是至关重要的。

🧠 [直觉心智模型]

把验证过程想象成一个侦探(验证器)破案。

  1. NP 案件: 侦探必须在很短的时间内(多项式时间)仅通过查看一小沓文件(多项式长度的证书)就能确认嫌疑人是否是罪犯。
  2. 题目描述的案件: 侦探被允许查看一整图书馆的书(指数长度的证书),并且他看书的时间和他看的书的数量成正比。虽然他“看书”这个动作本身很快,但他被允许看那么多的书,这给了他海量的时间和信息来破案,这种能力已经超出了普通“NP侦探”的范畴了。
💭 [直观想象]

想象你在参加一个开卷考试。

  1. NP 考试: 你可以在几小时内(关于问题长度的多项式时间)完成考试,并且你只被允许带一张A4纸作为参考资料(多项式长度的证书)。
  2. 题目描述的考试: 你也被允许在几小时内完成考试,但这个“几小时”是根据你带的参考资料的页数来计算的。而你被允许带任意多的参考资料,比如拉一卡车的书(指数长度的证书)。虽然你每看一页的速度很快,但因为你可以带无限的书,你实际上拥有了近乎无限的时间来寻找答案。这样的考试难度就大大降低了,不再是原来意义上的“NP考试”。

2.3. 问题 3

📜 [原文4]

  1. 所有 NP 完全问题都可以多项式时间归约到彼此。

答案:正确。这是一个证明。

设 $A, B$ 是 NP 完全的,我们想证明 $A \leq_{\mathrm{P}} B$。

我们知道 $B$ 是 NP 难的,因此它是 NP 完全的。所以对于任何 $L \in \mathrm{NP}$,我们有 $L \leq_{\mathrm{P}} B$。

由于 $A$ 是 NP 完全的,这意味着 $A \in \mathrm{NP}$。

结合这两点(取语言 $L=A$),我们有 $A \leq_{\mathrm{P}} B$。

📖 [逐步解释]

这个问题考察的是 NP-完全 (NP-Complete, NPC) 问题的定义和性质。让我们先分解 NP-完全 的定义。

一个语言(问题)$B$ 是 NP-完全的,如果它满足两个条件:

  1. $B \in \mathrm{NP}$:$B$ 本身是一个 NP 问题。这意味着存在一个多项式时间的验证器来验证 $B$ 的解。
  2. $B$ 是 NP-难 (NP-Hard):对于任何一个在 NP 中的语言 $L$,都存在一个多项式时间归约,记作 $L \leq_{\mathrm{P}} B$。这意味着 $L$ 的任何实例都可以通过一个多项式时间的转换函数,变成 $B$ 的一个实例,并且两者的答案(是/否)保持一致。通俗地说,$B$ 至少和 NP 中任何问题一样“难”。

现在题目说:任取两个 NP-完全 问题 $A$ 和 $B$,我们是否可以证明它们能相互进行多项式时间归约?也就是 $A \leq_{\mathrm{P}} B$ 并且 $B \leq_{\mathrm{P}} A$ 是否成立?答案的证明只展示了 $A \leq_{\mathrm{P}} B$,但 $B \leq_{\mathrm{P}} A$ 的证明是完全对称的。

让我们一步步跟随答案的逻辑:

  1. 目标: 证明 $A \leq_{\mathrm{P}} B$。
  2. 利用 $B$ 的性质: 我们知道 $B$ 是 NP-完全的,因此它一定是 NP-难的。
  3. 应用 NP-难 的定义: 根据 NP-难的定义,对于 NP 中的 任何 语言 $L$,都有 $L \leq_{\mathrm{P}} B$。这个 $L$ 可以是 NP 集合中的任何一个问题。
  4. 利用 $A$ 的性质: 我们也知道 $A$ 是 NP-完全的。根据 NP-完全定义的第一个条件,$A$ 本身必须在 NP 中,即 $A \in \mathrm{NP}$。
  5. 关键结合: 在第3步中,我们说结论对 任何 $L \in \mathrm{NP}$ 成立。现在,在第4步中,我们确认了 $A$ 就是 NP 中的一个成员。因此,我们可以把那个普适的 $L$ 具体化为我们眼前的 $A$。
  6. 得出结论: 将 $L=A$ 代入第3步的结论,我们直接得到 $A \leq_{\mathrm{P}} B$。

这个证明是完全正确的。由于 $A$ 和 $B$ 的地位是平等的,我们也可以用完全相同的方法,通过交换 $A$ 和 $B$ 的角色,来证明 $B \leq_{\mathrm{P}} A$。因此,所有 NP-完全 问题构成了一个等价类,它们在多项式时间归约的意义下,难度是完全相同的。

∑ [公式拆解]
  • NP-完全 (NPC): $A \in \mathrm{NPC}$ iff
  1. $A \in \mathrm{NP}$
  2. $\forall L \in \mathrm{NP}, L \leq_{\mathrm{P}} A$ (A is NP-Hard)
  • 多项式时间归约 ($L \leq_{\mathrm{P}} A$): 存在一个函数 $f$,它可以在多项式时间内被计算出来,使得对于任何输入 $x$,我们有:

$x \in L \iff f(x) \in A$

  • 证明 $A \leq_{\mathrm{P}} B$ for $A, B \in \mathrm{NPC}$:
  • 前提 1: $B \in \mathrm{NPC} \implies B$ is NP-Hard $\implies \forall L \in \mathrm{NP}, L \leq_{\mathrm{P}} B$.
  • 前提 2: $A \in \mathrm{NPC} \implies A \in \mathrm{NP}$.
  • 推导: 在前提1中,将 $L$ 替换为 $A$ (因为前提2告诉我们 $A$ 是 $L$ 的一个合法选择)。
  • 结论: $A \leq_{\mathrm{P}} B$.
💡 [数值示例]

这不是一个计算性问题,而是一个逻辑证明。但我们可以用具体的 NP-完全 问题来形象化。

  • 设 $A = \text{3-SAT}$ (三元可满足性问题)
  • 设 $B = \text{CLIQUE}$ (团问题)
  • 设 $C = \text{HAM-PATH}$ (哈密顿路径问题)

我们知道这三个问题都是 NP-完全的。

  • 证明 $\text{3-SAT} \leq_{\mathrm{P}} \text{CLIQUE}$:
  • 因为 CLIQUE 是 NP-难的,所以对任何 NP 问题 $L$ 都有 $L \leq_{\mathrm{P}} \text{CLIQUE}$。
  • 因为 3-SAT 是 NP-完全的,所以 $3\text{-SAT} \in \mathrm{NP}$。
  • 把 $L$ 替换成 3-SAT,我们就得到 $\text{3-SAT} \leq_{\mathrm{P}} \text{CLIQUE}$。
  • 证明 $\text{CLIQUE} \leq_{\mathrm{P}} \text{HAM-PATH}$:
  • 因为 HAM-PATH 是 NP-难的,所以对任何 NP 问题 $L$ 都有 $L \leq_{\mathrm{P}} \text{HAM-PATH}$。
  • 因为 CLIQUE 是 NP-完全的,所以 $\text{CLIQUE} \in \mathrm{NP}$。
  • 把 $L$ 替换成 CLIQUE,我们就得到 $\text{CLIQUE} \leq_{\mathrm{P}} \text{HAM-PATH}$。

这个逻辑可以无限传递下去,形成一个所有 NP-完全 问题之间的“全连接”归约网络。

⚠️ [易错点]
  1. 定义不清: 如果对 NP-完全NP-难 的定义不熟悉,就无法进行这个证明。关键在于理解 NP-难 的“对于所有 $L \in \mathrm{NP}$”这一全称量词的强大威力。
  2. 忘记 $A \in NP$: 在证明中,如果忘记了 $A$ 本身也是一个 NP 问题,就无法将它代入“所有 NP 问题都能归约到 B”这个模板中。
📝 [总结]

该论断是正确的。NP-完全的定义保证了这一点。任何一个 NP-完全 问题 $B$ 都是 NP-难的,意味着所有 NP 问题都能在多项式时间内归约到它。而另一个 NP-完全 问题 $A$ 恰好就是 NP 问题之一,因此 $A$ 必然能归约到 $B$。

🎯 [存在目的]

此题旨在检验学生是否深刻理解了 NP-完全 问题的核心性质,即它们是 NP 中“最难”的一类问题,并且所有这些“最难”的问题在难度上是等价的(在多项式时间归约下)。这解释了为什么我们只需要解决 一个 NP-完全 问题,就等于解决了所有 NP 问题。

🧠 [直觉心智模型]

想象一个“万能翻译机”俱乐部 (NP-Hard)。

  1. 任何一个俱乐部成员(比如 $B$),都拥有一本魔法书,可以把任何一本“NP语言”写的故事(比如 $L$)翻译成他们自己的语言。
  2. 现在有一个新成员 $A$ 想加入,他也是一个“万能翻译机”,所以他自己写的“NP故事” ($A \in \mathrm{NP}$) 也能被已有的成员 $B$ 用魔法书翻译。
  3. 因此,$A$ 的故事可以被翻译成 $B$ 的故事 ($A \leq_{\mathrm{P}} B$),反之亦然。俱乐部里的所有成员都能互相翻译对方的故事。
💭 [直观想象]

想象 NP-完全 问题是“万能钥匙”。

  1. 3-SAT 是一把万能钥匙,它可以打开 NP 里的所有锁。
  2. CLIQUE 也是一把万能钥匙,它也能打开 NP 里的所有锁。
  3. 那么,我们必然可以用 3-SAT 这把钥匙的模子,很快地(多项式时间)造出一把 CLIQUE 钥匙。反之亦然。它们本质上是同一把钥匙的不同形状而已。

2.4. 问题 4

📜 [原文5]

  1. 假设 图灵机 (TM) 的输入是一个以二进制给出的整数 $N$,并且 $M$ 运行时间为 $O\left(N^{2}\right)$,那么 $M$ 运行在多项式时间内。

答案:错误。$N$ 是以二进制作为输入给出的,因此输入大小为 $O\left(\log _{2}(N)\right)$。但是 $N^{2}= 2^{2 \log _{2}(N)}$,使用 $N=2^{\log _{2}(N)}$。因此运行时间是输入长度的指数级。

📖 [逐步解释]

这个问题考察的是对“输入大小”的精确理解,这是复杂性分析的基石。一个算法是否是多项式时间的,是比较其运行时间与 输入编码的长度,而不是输入所代表的 数值的大小

  1. 输入是什么? 输入是一个整数 $N$。
  2. 输入是如何编码的? 题目明确指出,它是以二进制形式给出的。
  3. 输入大小是多少? 一个整数 $N$ 的二进制表示所需要的位数大约是 $\log_2(N)$。所以,我们设输入大小(长度)为 $n = |\text{input}| \approx \log_2(N)$。
  4. 算法的运行时间是多少? 题目给出运行时间是 $O(N^2)$。这里的 $N$ 是数值本身。
  5. 判断是否为多项式时间: 我们需要判断运行时间 $O(N^2)$ 是否是输入大小 $n$ 的多项式。换句话说, $O(N^2)$ 是否可以表示为 $O(n^k)$ 的形式,其中 $k$ 是一个常数

让我们建立 $N$ 和 $n$ 之间的关系:

从 $n \approx \log_2(N)$,我们可以反解出 $N \approx 2^n$。

现在,我们将运行时间 $T(N) = O(N^2)$ 用输入大小 $n$ 来表示:

$T(n) = O((2^n)^2) = O(2^{2n})$。

这个结果 $O(2^{2n})$ 是一个关于输入大小 $n$ 的指数函数,而不是多项式函数 $O(n^k)$。因此,这个算法不是多项式时间的,而是指数时间的。

∑ [公式拆解]
  • 输入大小 (Input Size): $n = |\langle N \rangle_{binary}| = \lfloor \log_2 N \rfloor + 1 = O(\log N)$。这里 $\langle N \rangle_{binary}$ 表示 $N$ 的二进制编码。
  • 运行时间 (Running Time): $T(N) = O(N^2)$。这是一个关于数值 $N$ 的函数。
  • 目标: 将 $T$ 表示为关于输入大小 $n$ 的函数 $T(n)$。
  • 关系: 从 $n = O(\log N)$,我们有 $N = O(2^n)$。
  • 代换: 将 $N = O(2^n)$ 代入 $T(N) = O(N^2)$:

$T(n) = O((2^n)^2) = O(2^{2n})$.

  • 结论: $T(n) = O(2^{2n})$ 是 $n$ 的指数函数,不是 $n$ 的多项式 $O(n^k)$。所以该算法不是多项式时间的。
💡 [数值示例]
  • 示例 1:
  • 设整数 $N = 1024$。
  • 它的二进制表示是 10000000000,长度为 11 位。所以输入大小 $n=11$。($n = \log_2(1024) + 1 = 10+1=11$)。
  • 运行时间是 $O(N^2) = O(1024^2) \approx O(10^6)$。
  • 我们比较的是,运行时间 $10^6$ 和输入大小 $11$。
  • 示例 2:
  • 让我们将输入大小加倍,设 $n=22$。
  • 对应的数值 $N = 2^{21}-1$ 或类似的数,大约是 $2 \cdot 10^6$。
  • 运行时间是 $O(N^2) \approx O((2 \cdot 10^6)^2) = O(4 \cdot 10^{12})$。
  • 观察:输入大小 $n$ 从 11 增加到 22(增加了1倍),而运行时间从 $10^6$ 级别增加到 $4 \cdot 10^{12}$ 级别(增加了约 $4 \cdot 10^6$ 倍),这是一个典型的指数增长行为。如果它是多项式的,比如 $O(n^k)$,那么当 $n$ 加倍时,运行时间应该大约增加 $2^k$ 倍,是一个小常数倍。
⚠️ [易错点]
  1. 根本性混淆: 最常见的错误就是将数值 $N$ 本身当作输入大小。在理论计算机科学中,输入大小永远是指描述输入所需的比特(或字符)数。
  2. 伪多项式时间: 像本题中 $O(N^2)$ 这样的算法,其运行时间是输入数值的多项式,但却是输入长度的指数,被称为伪多项式时间 (Pseudo-polynomial time) 算法。例如,对背包问题的动态规划解法就是伪多项式时间的。
  3. 一元编码 vs. 二进制编码: 如果题目说输入是以“一元编码”(unary)给出的(例如,数字5表示为'11111'),那么数值 $N$ 的输入大小就是 $O(N)$。在这种情况下,$O(N^2)$ 的运行时间就是输入大小的多项式 $O(n^2)$。编码方式至关重要。
📝 [总结]

这个判断是错误的。算法的复杂性必须根据其输入的 编码长度 来衡量。对于一个以二进制编码的数 $N$,其编码长度约为 $\log N$。一个 $O(N^2)$ 的运行时间,当用编码长度 $n \approx \log N$ 来表示时,变为 $O((2^n)^2) = O(2^{2n})$,这是一个指数级的复杂性,而非多项式级。

🎯 [存在目的]

此题旨在强调复杂性分析中一个至关重要且容易出错的细节:区分输入数值和输入大小(编码长度)。它引入了伪多项式时间这一重要概念,并阐明了为何某些看似“多项式”的算法实际上是指数级的。

🧠 [直觉心智模型]

想象你要邮寄一笔钱。

  1. 输入数值 N: 是你要寄的钱的总额,比如 $1,000,000$ 美元。
  2. 输入大小 n: 是你用来写这张支票所用的墨水量。支票上写 "$1,000,000$" 只需要几个字符。$n$ 很小。
  3. 运行时间 T(N): 银行处理这笔钱所需的时间。假设银行每处理1美元就需要1秒,那么处理 $N$ 美元就需要 $N$ 秒。
  4. 判断: 处理时间 $N$ 秒,相对于你写支票的墨水量 $n$ 来说,是不是一个“合理”的时间?不是。因为 $N$ 相对于 $n$ 是指数关系 ($N \approx 10^n$)。银行的处理时间是指数级的慢。
💭 [直观想象]

想象你在数米。

  1. 输入数值 N: 是一袋米里有多少粒米。比如 $N = 2^{64}-1$ 粒。
  2. 输入大小 n: 是描述这个数字所用的位数,只需要64比特。这是一个很短的描述。
  3. 运行时间 T(N): 你要一粒一粒地数完这袋米,所需的时间正比于 $N$。
  4. 结论: 相对于你听到“$2^{64}-1$”这个简短指令所花的时间($O(n)$),你实际数米所花的时间($O(N) = O(2^n)$)是极其漫长的,是指数级的。

33. 练习 2:证明 NP 在并运算下是封闭的

📜 [原文6]

练习 2。证明 NP 在运算下是封闭的。也就是说,如果 $L_{1}, L_{2} \in \mathrm{NP}$,那么 $L_{1} \cup L_{2} \in \mathrm{NP}$。

设 $L_{1}, L_{2} \in \mathrm{NP}$。那么根据定义,存在一个多项式时间验证器 $V_{1}$,使得:

$$ x \in L_{1} \Leftrightarrow \exists c_{1} \text { such that } V_{1}\left(x, c_{1}\right) \text { accepts. } $$

类似地,我们有一个多项式时间验证器 $V_{2}$ 用于 $L_{2}$,使得:

$$ x \in L_{2} \Leftrightarrow \exists c_{2} \text { such that } V_{2}\left(x, c_{2}\right) \text { accepts. } $$

我们现在想为 $L_{1} \cup L_{2}$ 构建一个多项式时间验证器 $V$。思路是给定 $c$,我们首先运行 $V_{1}$ 检查它是否接受,然后运行 $V_{2}$。如果其中任何一个接受,我们就接受;如果两者都拒绝,我们就拒绝。

```

Algorithm 1 A verifier for $L_{1} \cup L_{2}$

Input: $x, c$

Run $V_{1}$ on $x, c \quad \bullet V_{1}$ runs in polynomial time in $|x|$

if $V_{1}$ accepts then

Accept $x$

end if

Run $V_{2}$ on $x, c \quad \bullet V_{2}$ runs in polynomial time in $|x|$

if $V_{2}$ accepts then

Accept $x$

end if

Reject.

```

首先,很明显 $V$ 运行时间是 $|x|$ 的多项式,因为它所做的只是在 $x, c$ 上运行 $V_{1}, V_{2}$ ²。

所以剩下要证明的是

$$ x \in L_{1} \cup L_{2} \Longleftrightarrow \exists c \text { such that } V(x, c) \text { accepts. } $$

假设 $x \in L_{1} \cup L_{2}$,我们想证明存在一个 $c$ 使得 $V(x, c)$ 接受。如果 $x \in L_{1}$,我们知道存在一个 $c_{1}$ 使得 $V_{1}\left(x, c_{1}\right)$ 接受。因此取 $c=c_{1}$ 会导致 $V$ 接受。

否则,如果 $x \in L_{2}$,我们知道存在一个 $c_{2}$ 使得 $V_{2}\left(x, c_{2}\right)$ 接受。因此取 $c=c_{2}$ 会导致 $V$ 接受。

因此

$$ x \in L_{1} \cup L_{2} \Rightarrow \exists c \text { such that } V(x, c) \text { accepts } $$

我们现在证明另一个方向。假设存在一个 $c$ 使得 $V(x, c)$ 接受。那么在伪代码中,要么 $V_{1}(x, c)$ 接受,要么 $V_{2}(x, c)$ 接受。如果 $V_{1}$ 接受,那么根据定义

$$ V_{1}(x, c) \text { accepts } \Rightarrow x \in L_{1} $$

否则,如果 $V_{2}$ 接受,那么根据定义

$$ V_{2}(x, c) \text { accepts } \Rightarrow x \in L_{2} $$

无论如何,都必须是 $x \in L_{1} \cup L_{2}$。所以 $V(x, c)$ 接受 $\Rightarrow x \in L_{1} \cup L_{2}$。

📖 [逐步解释]

这个问题要求证明 NP 类对于运算是封闭的。所谓“封闭”,是指对集合中的成员进行某种运算后,结果仍然在该集合中。这里,集合是 NP,运算是集(Union)。也就是说,如果 $L_1$ 和 $L_2$ 都是 NP 问题,那么它们俩的并集 $L_1 \cup L_2$ 也一定是一个 NP 问题。

要证明 $L_1 \cup L_2 \in \mathrm{NP}$,我们需要根据 NP 的定义,为其构造一个多项式时间的验证器。我们称这个新的验证器为 $V$。

证明思路

  1. 利用已知条件: 我们知道 $L_1$ 和 $L_2$ 都在 NP 中。这意味着它们各自都有一个多项式时间的验证器,我们称之为 $V_1$ 和 $V_2$。
  2. 构造新验证器 $V$: 我们要为 $L_1 \cup L_2$ 设计一个新的验证器 $V$。一个字符串 $x$ 属于 $L_1 \cup L_2$ 的意思是,$x$ 要么属于 $L_1$,要么属于 $L_2$(或者两者都属于)。
    • 那么,一个能证明 $x \in L_1 \cup L_2$ 的证据(证书 $c$),应该是什么样的呢?它应该要么是能让 $V_1$ 接受的证据,要么是能让 $V_2$ 接受的证据。
    • 所以,我们的新验证器 $V$ 在拿到输入 $x$ 和证书 $c$ 后,可以这么做:它先把 $c$ 当作是给 $V_1$ 的证书,运行 $V_1(x, c)$。如果 $V_1$ 接受了,太好了,这说明 $x \in L_1$,那么 $x$ 自然就在 $L_1 \cup L_2$ 中,所以 $V$ 可以立刻接受。
    • 如果 $V_1$ 拒绝了,也没关系。$V$ 再把 $c$ 当作是给 $V_2$ 的证书,运行 $V_2(x, c)$。如果 $V_2$ 接受了,说明 $x \in L_2$,那么 $x$ 也自然在 $L_1 \cup L_2$ 中,所以 $V$ 也应该接受。
    • 如果 $V_1$ 和 $V_2$ 都拒绝了 $c$,那么这个证书 $c$ 无法证明 $x$ 属于 $L_1$ 或 $L_2$。$V$ 就应该拒绝。
  3. 证明 $V$ 是一个合法的NP验证器:
    • 时间复杂性分析: $V$ 的操作包括运行 $V_1$ 和运行 $V_2$。因为 $V_1$ 和 $V_2$ 都是多项式时间的(比如分别是 $O(|x|^{k_1})$ 和 $O(|x|^{k_2})$),那么顺序执行它们俩的总时间就是 $O(|x|^{k_1}) + O(|x|^{k_2})$,这仍然是 $|x|$ 的一个多项式时间 $O(|x|^{\max(k_1, k_2)})$。所以 $V$ 是高效的。
    • 正确性证明 (完备性与可靠性): 这需要证明双向蕴含关系 $x \in L_{1} \cup L_{2} \Longleftrightarrow \exists c \text { such that } V(x, c) \text { accepts}$。
    • ($\Rightarrow$) 正向证明 (完备性):
    • 假设 $x \in L_1 \cup L_2$。我们需要证明存在一个证书 $c$ 能让 $V$ 接受。
    • 分两种情况:
    • Case 1: $x \in L_1$。因为 $L_1 \in \mathrm{NP}$,所以必然存在一个证书 $c_1$ 使得 $V_1(x, c_1)$ 接受。那么,我们让新验证器 $V$ 使用这个 $c_1$ 作为证书,即 $c=c_1$。根据 $V$ 的设计,它会运行 $V_1(x, c_1)$,发现 $V_1$ 接受了,于是 $V$ 就会接受。我们找到了一个让 $V$ 接受的证书。
    • Case 2: $x \in L_2$。同理,存在一个证书 $c_2$ 使得 $V_2(x, c_2)$ 接受。我们让 $V$ 使用 $c=c_2$ 作为证书。$V$ 先运行 $V_1(x, c_2)$ (可能会拒绝),然后运行 $V_2(x, c_2)$,发现 $V_2$ 接受了,于是 $V$ 接受。我们也找到了一个让 $V$ 接受的证书。
    • 综上,只要 $x \in L_1 \cup L_2$,就一定能找到一个证书让 $V$ 接受。
    • ($\Leftarrow$) 反向证明 (可靠性):
    • 假设存在一个证书 $c$ 使得 $V(x, c)$ 接受。我们需要证明 $x \in L_1 \cup L_2$。
    • 根据 $V$ 的算法,它接受只可能是两种情况之一:要么是 $V_1(x, c)$ 接受了,要么是 $V_2(x, c)$ 接受了。
    • 如果 $V_1(x, c)$ 接受,根据 $V_1$ 是 $L_1$ 的验证器,我们知道 $x \in L_1$。
    • 如果 $V_2(x, c)$ 接受,根据 $V_2$ 是 $L_2$ 的验证器,我们知道 $x \in L_2$。
    • 既然 $x \in L_1$ 或者 $x \in L_2$,那么根据并集的定义,必然有 $x \in L_1 \cup L_2$。
  4. 结论: 我们成功地为 $L_1 \cup L_2$ 构建了一个多项式时间的验证器 $V$,并证明了其正确性。因此,根据 NP 的定义,$L_1 \cup L_2 \in \mathrm{NP}$。NP运算下是封闭的。
∑ [公式拆解]
  • $L_{1} \cup L_{2}$: 语言 $L_1$ 和 $L_2$ 的集。一个字符串 $x$ 在这个集合中,当且仅当 $x$ 在 $L_1$ 中,或者 $x$ 在 $L_2$ 中。
  • $x \in L_{1} \Leftrightarrow \exists c_{1} \text { such that } V_{1}\left(x, c_{1}\right) \text { accepts. }$
  • 这是 NP 语言 $L_1$ 的形式化定义。
  • $\Leftrightarrow$ (iff): 当且仅当,表示左右两边的命题是等价的。
  • $\exists c_1$: 存在一个证书 $c_1$。
  • $V_1(x, c_1)$ accepts: 验证器 $V_1$ 在输入 $x$ 和证书 $c_1$ 时输出“接受”。
  • $x \in L_{1} \cup L_{2} \Longleftrightarrow \exists c \text { such that } V(x, c) \text { accepts. }$
  • 这是我们要为新语言 $L_1 \cup L_2$ 证明的目标。我们必须展示存在一个这样的验证器 $V$ 和相应的证书 $c$。
💡 [数值示例]
  • 设 $L_1 = \text{CLIQUE}$ (团问题):判断图 $G$ 是否包含一个大小为 $k$ 的团。
  • 设 $L_2 = \text{HAM-PATH}$ (哈密顿路径问题):判断图 $G$ 是否存在一条访问所有顶点的路径。
  • 两者都是 NP 问题。
  • 现在考虑语言 $L = L_1 \cup L_2$。一个输入 $\langle G, k \rangle$ 属于 $L$,当且仅当图 $G$ 中要么有一个 $k$-团,要么有一条哈密顿路径。
  • 构造验证器 $V$ for $L$:
  • 输入: $\langle G, k \rangle$ 和一个证书 $c$。
  • 步骤1: 将 $c$ 视为 CLIQUE 问题的证书(即一个顶点列表)。运行 $V_{CLIQUE}(\langle G, k \rangle, c)$。
  • 示例证书 $c_1$: 假设 $c_1 = \{v_1, v_5, v_8\}$ 是一个大小为3的顶点集。$V_{CLIQUE}$ 会检查这3个点之间是否两两都有边。如果是,它接受。
  • 如果 $V_{CLIQUE}$ 接受了,那么 $V$ 立刻接受。
  • 步骤2: 如果 $V_{CLIQUE}$ 拒绝,则将 $c$ 视为 HAM-PATH 问题的证书(即一个顶点序列)。运行 $V_{HAM-PATH}(\langle G, k \rangle, c)$。
  • 示例证书 $c_2$: 假设 $c_2 = (v_3, v_1, v_2, v_4)$ 是一个顶点序列。$V_{HAM-PATH}$ 会检查这个序列是否是图中的一条有效路径,并且是否访问了所有顶点。如果是,它接受。
  • 如果 $V_{HAM-PATH}$ 接受了,那么 $V$ 接受。
  • 步骤3: 如果两者都拒绝, $V$ 拒绝。
  • 时间分析: 验证团和验证哈密顿路径都是图规模的多项式时间操作。两者相加仍然是多项式时间
  • 正确性:
  • 如果图 $G$ 有一个 $k$-团,那么存在证书 $c_1$(该团的顶点集),使得 $V$ 在步骤1接受。
  • 如果图 $G$ 有一条哈密顿路径,那么存在证书 $c_2$(该路径的顶点序列),使得 $V$ 在步骤2接受。
  • 如果 $V$ 接受了,那必然是 $V_{CLIQUE}$ 或 $V_{HAM-PATH}$ 接受了,说明图 $G$ 要么有团要么有哈密顿路径。
⚠️ [易错点]
  1. 证书的通用性: 在构造的验证器 $V$ 中,证书 $c$ 被先后用于 $V_1$ 和 $V_2$。一个为 $L_1$ 设计的有效证书 $c_1$ 可能对于 $V_2$ 来说是无意义的垃圾输入,反之亦然。但这没关系,因为验证器只需要对“好”的证书有反应。只要存在 一种 能让它通过的证书即可。
  2. 错误的构造: 可能会想设计一个更复杂的证书,比如 $c = \langle b, c' \rangle$,其中 $b$ 是一个比特位指示该用 $V_1$ 还是 $V_2$,$c'$ 是真正的证书。这也是可行的,并且在某些证明中更清晰,但原文中更简单的“一证两用”模型同样正确,因为它满足“存在一个证书”的条件。
  3. 对“封闭”概念的理解: 要理解“封闭”是集合论中的一个通用概念,指的是运算结果的归属性。类似地,可以证明 P, co-NP, PSPACE 等复杂性类在等运算下的封闭性。
📝 [总结]

该证明通过构造法,为两个 NP 语言的集 $L_1 \cup L_2$ 设计了一个新的多项式时间验证器 $V$。这个 $V$ 顺序地调用 $L_1$ 和 $L_2$ 各自的验证器 $V_1$ 和 $V_2$,只要其中任意一个接受证书,新的验证器 $V$ 就接受。通过严谨地证明这个新验证器的时间复杂性和正确性,可以得出结论:$L_1 \cup L_2$ 仍属于 NP,故 NP运算是封闭的。

🎯 [存在目的]

这个练习的目的是让学生练习使用复杂性类的形式化定义(这里是 NP 的验证器模型)来证明其基本性质(闭包性质)。这是理论计算机科学中一种常见的证明模式,有助于加深对复杂性类本质的理解。

🧠 [直觉心智模型]

NP 问题想象成需要“门票”才能进入的俱乐部。

  1. $L_1$ 是“科幻迷俱乐部”,你需要一张科幻电影的票根(证书 $c_1$)才能通过门卫 $V_1$ 的检查。
  2. $L_2$ 是“摇滚乐迷俱乐部”,你需要一张摇滚音乐会的票根(证书 $c_2$)才能通过门卫 $V_2$ 的检查。
  3. $L_1 \cup L_2$ 是一个联合俱乐部,叫“科幻或摇滚俱乐部”。它的门卫 $V$ 的规则是:只要你出示的票根(证书 $c$)能被 $V_1$ 或者 $V_2$ 认证,你就可以进入。
  4. 显然,如果你有任何一种票,你都能进去。这个联合俱乐部的“检票”过程(验证)也是高效的(先后问两个门卫),所以它也是一个“NP俱乐部”。
💭 [直观想象]

想象一个双重安检系统。你要进入一个大楼,这座大楼有两个入口,一个通往A公司,一个通往B公司。

  1. A公司的门禁 $V_1$ 需要A公司的员工卡 $c_1$。
  2. B公司的门禁 $V_2$ 需要B公司的员工卡 $c_2$。
  3. 大楼的入口规则是:只要你能刷开A或B中任意一个门,你就可以进入大楼。
  4. 你(输入 $x$)来到大楼门口,拿出你的卡(证书 $c$)。你先在A公司的读卡器上刷一下,如果门开了,你就进去了。如果没开,你又在B公司的读卡器上刷一下,如果开了,你也进去了。如果都没开,你就进不来。
  5. 这个“进入大楼”问题的验证过程,就是先后尝试两个已知的快速验证过程。总过程自然也是快速的。

44. 练习 3:k-Clique 与 Clique

4.1. 固定 k 的 k-Clique 问题

📜 [原文7]

  • 固定某个常数 $k$。问题 $k$-Clique 定义如下:输入是一个图 $G$, $G$ 是一个有 $n$ 个节点的图。您可以将 $G$ 视为由一个 $n \times n$ 二进制矩阵 $A$ 描述,其中 $A_{i, j}=1$ 当且仅当 $G$ 中存在边 $(i, j)$(因此输入大小是 $n^{2}$)。当且仅当 $G$ 中存在 $k$ 个顶点的子集 $V^{*}$,使得这些顶点形成一个完全图(任意两个节点之间都有一条边)时,您必须接受 $G$。为什么这个问题在 P 中?

我们可以给出以下多项式时间算法来解决这个问题:

```

Algorithm 2 An algorithm for $k$-Clique

Input: $\langle G\rangle$ where $G$ is a graph

```

```

for all subset $S$ of $k$ vertices from $G$ do

Check that for each pairs $(u, v)$, with $u, v \in S$ we have that $(u, v)$ is an edge in $G$.

▷ This means the vertices in $S$ form a complete graph.

If for all pairs, the edge ( $u, v$ ) is in $G$, accept.

end for

Reject.

```

这个算法基本上查看 $G$ 中所有 $k$ 个顶点的子集,并检查它们是否形成一个完全图。显然,如果 $\langle G\rangle \in k$-Clique,那么我们将接受,否则我们将拒绝。

在算法中,我们查看 $G$ 中所有 $\binom{n}{k}$ 个 $k$ 个顶点的子集。对于每个子集,我们需要检查 $O\left(k^{2}\right)$ 条边是否存在,每对一个。由于 $k$ 是一个常数,我们可以假设这需要常数时间。因此算法的运行时间是 $O\left(n^{k}\right)$。由于 $k$ 是一个常数,这是多项式时间

📖 [逐步解释]

这个问题探讨了当 团 (Clique) 问题中的团大小 $k$ 是一个固定的常数时,其复杂性。我们要证明 $k$-Clique 问题属于 P 类,即存在一个多项式时间的确定性算法来解决它。

问题定义:

  • 输入: 一个有 $n$ 个顶点的图 $G$。
  • 参数: 一个固定的常数 $k$ (比如 $k=3, k=5, k=100$)。注意 $k$ 不是输入的一部分。
  • 问题: 图 $G$ 中是否存在一个大小为 $k$ 的顶点子集,其中任意两个顶点之间都有边相连(即形成一个 $k$-团)?

算法思路 (暴力搜索):

既然我们要找一个大小为 $k$ 的特定子集,最直接的方法就是检查所有可能性。

  1. 从图 $G$ 的 $n$ 个顶点中,枚举出所有可能的大小为 $k$ 的顶点子集。
  2. 对于每一个枚举出的子集 $S$,检查它是否构成一个团。
    • 如何检查?对子集 $S$ 中的任意一对顶点 $(u, v)$,都去查询图 $G$ 中是否存在边 $(u,v)$。
    • 如果对于所有顶点对,边都存在,那么恭喜,我们找到了一个 $k$-团。算法可以立即停止并返回“是”。
  3. 如果检查完所有的大小为 $k$ 的子集后,都没有找到一个团,那么图中就不存在 $k$-团。算法返回“否”。

时间复杂性分析:

这是证明的关键部分。我们要分析上述算法的运行时间是否是输入大小 $n$ 的多项式

  1. 输入大小: 图 $G$ 有 $n$ 个顶点,可以用一个 $n \times n$ 的邻接矩阵表示,所以输入大小是 $O(n^2)$。我们的复杂性要与 $n$ 进行比较。
  2. 步骤1的计算量: 从 $n$ 个顶点中选取 $k$ 个组成一个子集,总共有 $\binom{n}{k}$ 种组合。

$\binom{n}{k} = \frac{n!}{k!(n-k)!} = \frac{n(n-1)\dots(n-k+1)}{k!}$

由于 $k$ 是一个常数, $k!$ 也是一个常数。上式的分子是一个关于 $n$ 的 $k$ 次多项式。因此,$\binom{n}{k} = O(n^k)$。

  1. 步骤2的计算量: 对于每一个大小为 $k$ 的子集 $S$,我们需要检查其中所有顶点对。一个大小为 $k$ 的集合有 $\binom{k}{2} = \frac{k(k-1)}{2}$ 对顶点。检查每对顶点之间是否有边,在邻接矩阵中只需要 $O(1)$ 的时间。

由于 $k$ 是一个常数,$\binom{k}{2}$ 也是一个常数。所以,检查一个子集是否为团的时间是 $O(k^2)$,也就是常数时间

  1. 总运行时间: 总时间 = (子集数量) $\times$ (检查每个子集的时间)

$T(n) = O(n^k) \times O(k^2)$

因为 $k$ 是常数,所以 $O(k^2)$ 也是常数。因此,总运行时间是 $T(n) = O(n^k)$。

  1. 结论: 运行时间 $O(n^k)$ 是一个关于 $n$ 的多项式(因为指数 $k$ 是常数)。因此,$k$-Clique 问题属于 P 类。
∑ [公式拆解]
  • k-Clique: 一个问题族,对每个常数 $k$ 有一个具体问题。例如, 3-Clique, 4-Clique。
  • P 类: 所有可以由一个确定性图灵机多项式时间内解决的判定问题的集合。
  • $\binom{n}{k}$: 从 $n$ 个元素中无序地选取 $k$ 个元素的组合数。

$\binom{n}{k} = \frac{n(n-1)\cdots(n-k+1)}{k!}$。当 $k$ 是常数时,分母是常数,分子是 $n$ 的 $k$ 次多项式,所以 $\binom{n}{k} = O(n^k)$。

  • $O(n^k)$: 运行时间是 $n$ 的 $k$ 次多项式。因为 $k$ 是常数,所以这符合 P 类的要求。
💡 [数值示例]
  • 示例 1: 3-Clique 问题 ($k=3$)。输入一个有 $n=5$ 个顶点的图 $G$。
  • 算法需要检查所有大小为3的顶点子集。数量是 $\binom{5}{3} = \frac{5 \cdot 4 \cdot 3}{3 \cdot 2 \cdot 1} = 10$ 个。
  • 对于每个子集,比如 $\{v_1, v_2, v_3\}$,需要检查3条边是否存在:$(v_1, v_2), (v_1, v_3), (v_2, v_3)$。检查一个子集的时间是常数
  • 总运行时间大致与 $10 \times 3$ 成正比。
  • 算法的运行时间是 $O(n^3)$。这是一个多项式时间算法。
  • 示例 2: 100-Clique 问题 ($k=100$)。输入一个有 $n=1000$ 个顶点的图 $G$。
  • $k=100$ 是一个固定的常数
  • 算法需要检查 $\binom{1000}{100}$ 个子集。这是一个天文数字,在实践中完全不可行。
  • $\binom{1000}{100} \approx \frac{1000^{100}}{100!}$
  • 算法的运行时间是 $O(n^{100})$。
  • 尽管这个算法非常慢,但在理论复杂性的分类中,因为指数 $100$ 是一个常数,所以 $O(n^{100})$ 仍然被认为是多项式时间。因此 100-Clique 问题在 P 中。这凸显了理论复杂性与实践可行性之间的区别。
⚠️ [易错点]
  1. 常数 k 的重要性: 这个结论的核心在于 $k$ 是一个不随输入 $n$ 变化的常数。如果 $k$ 是变量,结论将完全不同。
  2. 理论 vs. 实践: 学生可能会因为 $O(n^{100})$ 这样的算法在现实中无法运行而感到困惑。必须分清复杂性理论中的“多项式时间”是一个理论分类,它旨在区分多项式增长和指数增长这两种性质根本不同的增长模式,而不是用来衡量一个算法是否“实用”。
📝 [总结]

当团的大小 $k$ 是一个固定的常数时,$k$-Clique 问题可以通过暴力枚举所有大小为 $k$ 的顶点子集并在多项式时间内解决。算法的运行时间是 $O(n^k)$,由于 $k$ 是常数,这是一个多项式时间算法,因此 $k$-Clique 问题属于 P 类。

🎯 [存在目的]

此部分的目的是为了与下一部分的通用 Clique 问题形成鲜明对比。它展示了问题参数(如 $k$)是常数还是变量,会如何根本性地改变问题的复杂性,将其从 P 类问题变为 NP-完全 问题。

🧠 [直觉心智模型]
  1. k-Clique: 想象你在一个有 $n$ 个人的派对上,要找一个 5 人小团体($k=5$),他们彼此都认识。你的策略是:把所有可能的 5 人组合都试一遍(一个 $O(n^5)$ 的过程),对每个组合,问他们是不是互相都认识。虽然很累,但这是一个有固定步骤、保证能完成的“机械”任务。任务的难度只和派对总人数 $n$ 有关,找 5 个人这个目标是固定的。
💭 [直观想象]

想象你在一个沙滩上找贝壳。

  1. k-Clique: 你的任务是“找到3个($k=3$)完全一样的扇贝”。你把沙滩上所有贝壳三个三个地组合起来看,检查每一组是不是都一样。虽然贝壳总数 $n$ 可能很大,但你每次比较的目标数量是固定的3个。这是一个多项式时间的任务。

4.2. k 作为输入的 Clique 问题

📜 [原文8]

  • NP 完全问题 Clique 定义如下:输入是一个图 $G$, $G$ 是一个有 $n$ 个节点的图。但现在 $k$ 以十进制作为输入给出。(因此输入大小大约是 $\left(n^{2}+\log _{10}(k)\right)$)。同样,当且仅当 $G$ 中存在 $k$ 个顶点的子集 $V^{*}$,使得这些顶点形成一个完全图时,您必须接受 $G$。为什么之前的证明无法证明这个问题在 P 中?

如果我们要修改上述算法来证明这一点,它会是这样的:

```

Algorithm 3 An algorithm for Clique

Input: $\langle G, k\rangle \quad \triangleright k$ is now part of the input

for all subset $S$ of $k$ vertices from $G$ do

Check that for each pairs $(u, v) \in S(u, v)$ is an edge in $G$.

if for all pairs, the edge ( $u, v$ ) is in $G$ then

Accept.

end if

end for

Reject.

```

想象输入是 $\left(G, k=\frac{n}{2}\right)$。那么,算法将不得不查看 $\binom{n}{\frac{n}{2}}$ 个子集,但这

大约是 $2^{n}$ 个子集。然而,输入大小只有 $n^{2}+\log _{10}(n)$,因此算法的运行时间是指数级的。³

📖 [逐步解释]

这个问题解释了为什么当团的大小 $k$ 成为输入的一部分时,前面用于证明 $k$-Clique $\in \mathrm{P}$ 的算法不再是多项式时间的。这正是通用 Clique 问题是 NP-完全 而非 P 类问题的关键所在。

问题定义的变化:

  • 输入: 一个图 $G$(大小 $O(n^2)$)和 一个整数 $k$(大小 $O(\log k)$)。
  • 总输入大小: 约为 $O(n^2 + \log k)$。
  • 问题: 图 $G$ 中是否存在一个大小为 $k$ 的团?

分析之前的算法:

我们仍然使用相同的暴力搜索算法:枚举所有大小为 $k$ 的子集并检查。

  • 运行时间: $T(n, k) = O(\binom{n}{k} \cdot k^2)$。

为什么不再是多项式时间?

关键在于,现在的运行时间必须与总输入大小 $O(n^2 + \log k)$ 进行比较。

让我们考虑一个最坏情况的例子,正如原文所建议的:

  • 设 $k = n/2$。这是一个非常合理的情形,因为 $k$ 是输入的一部分,它可以是 $n$ 的一个函数。
  • 输入大小: $O(n^2 + \log(n/2)) = O(n^2)$。
  • 算法运行时间:
  • 算法需要检查 $\binom{n}{n/2}$ 个子集。
  • 使用斯特林公式近似,我们知道 $\binom{n}{n/2} \approx \frac{2^n}{\sqrt{\pi n/2}}$。这是一个指数级别的数量,为 $O(2^n / \sqrt{n})$。
  • 每个子集的检查时间是 $O(k^2) = O((n/2)^2) = O(n^2)$。
  • 总运行时间 $T(n) = O(\frac{2^n}{\sqrt{n}} \cdot n^2)$。

现在我们来比较:

  • 运行时间: $O(2^n \cdot n^{1.5})$,这是一个关于 $n$ 的指数函数。
  • 输入大小: $O(n^2)$,这是一个关于 $n$ 的多项式函数。

由于运行时间是输入大小的指数函数,而不是多项式函数,所以这个算法不是多项式时间算法。

为什么之前的证明失效了?

之前的证明依赖于一个关键假设:$T(n) = O(n^k)$ 是一个多项式时间,因为指数 $k$ 是一个常数

但是现在,指数 $k$ 本身就是输入的一部分,是一个变量。当 $k$ 可以随 $n$ 变化时(例如 $k=n/2$),运行时间 $O(n^k)$ 就变成了 $O(n^{n/2})$,这显然不是一个多项式函数。

∑ [公式拆解]
  • 通用 Clique 问题: 输入 $\langle G, k \rangle$。$n=|V(G)|$。
  • 输入大小: $|input| = O(n^2 + \log k)$。
  • 暴力算法运行时间: $T(n, k) = O(\binom{n}{k} \cdot k^2)$。
  • 最坏情况分析 (Worst-Case Analysis): 选取一个能让算法运行最慢的 $k$。通常 $k$ 在 $n/2$ 附近时,$\binom{n}{k}$ 最大。
  • 当 $k = n/2$:
  • $|input| = O(n^2)$。
  • $T(n, n/2) = O(\binom{n}{n/2} \cdot (n/2)^2) = O(\frac{2^n}{\sqrt{n}} \cdot n^2)$。
  • 比较: 令输入大小为 $m = O(n^2)$, 则 $n = O(\sqrt{m})$。

$T(m) = O(\frac{2^{O(\sqrt{m})}}{\sqrt{O(\sqrt{m})}} \cdot (O(\sqrt{m}))^2) = O(2^{c\sqrt{m}} \cdot m^{3/4})$。

这个函数 $T(m)$ 是 $m$ 的指数函数(或严格来说,准指数),而不是多项式 $O(m^c)$。

💡 [数值示例]
  • 示例 1: 设 $n=40$, $k=20$。
  • 输入大小: $n^2 + \log(20) \approx 1600 +$ 几比特,主要是 $O(n^2)$。
  • 运行时间: 需要检查 $\binom{40}{20}$ 个子集。$\binom{40}{20} \approx 1.37 \times 10^{11}$,即超过一千亿个。
  • 这是一个巨大的计算量,源于 $k$ 不再是一个小的常数
  • 示例 2: 对比 $k=3$ (常数) vs $k=n/2$ (变量)
  • 设 $n=30$。
  • 3-Clique: 运行时间 $O(n^3) = O(30^3) = O(27000)$。多项式
  • (n/2)-Clique (即 15-Clique): 运行时间 $O(\binom{30}{15}) \approx O(1.5 \times 10^8)$。
  • 现在设 $n=60$。
  • 3-Clique: 运行时间 $O(n^3) = O(60^3) = O(216000)$。增加了 $2^3=8$ 倍。
  • (n/2)-Clique (即 30-Clique): 运行时间 $O(\binom{60}{30}) \approx O(1.18 \times 10^{17})$。增长了远远不止多项式倍。
⚠️ [易错点]
  1. 固定思维: 沿用 $k$-Clique 的思路,认为 $O(n^k)$ 总是多项式的,而没有意识到 $k$ 已经从常数变成了变量。
  2. 对“多项式时间”的误解: 再次强调,多项式时间是指运行时间是 输入大小多项式。当 $k$ 成为输入的一部分时,$k$ 本身的大小是 $\log k$,非常小,但它对运行时间的影响(作为指数)却是巨大的。
📝 [总结]

当 $k$ 作为输入的一部分时,之前用于 $k$-Clique 问题的暴力枚举算法的运行时间 $O(\binom{n}{k} k^2)$ 不再是输入大小 $O(n^2 + \log k)$ 的多项式。在 $k=n/2$ 等最坏情况下,其运行时间会变成输入大小的指数函数。这解释了为什么该算法不能证明通用 Clique 问题属于 P 类,并暗示了其内在的困难性(实际上是 NP-完全的)。

🎯 [存在目的]

这部分的存在是为了与前一部分形成对比,清晰地揭示了问题参数从常数变为变量是如何导致复杂性P 急剧跃升到 NP-完全的。这是理解复杂性理论中参数化复杂性思想的入门。

🧠 [直觉心智模型]
  1. 通用 Clique: 想象派对任务变了,不再是找固定的5人小团体。你的任务卡上写着:“派对上有 $n$ 个人,请找出一个 $k$ 人小团体,他们彼此都认识”。而这个 $k$ 是任务卡上临时写的,可能是5,也可能是 $n/2$。
  2. 如果 $k=n/2$,你的任务变成了“找出一半的人,他们彼此都认识”。你的旧策略“检查所有组合”现在变得不切实际,因为组合的数量会随着派对规模的增大而爆炸性增长。任务的难度不再仅仅和 $n$ 有关,还和 $k$ 这个可变的、可能很大的目标有关。
💭 [直观想象]
  1. 通用 Clique: 沙滩找贝壳的任务现在是:“这里有一堆贝壳,请找到 $k$ 个完全一样的扇贝”,而 $k$ 是我临时告诉你的数字。如果我说 $k=3$,任务还很简单。但如果沙滩上有1000个贝壳,我让你找 $k=500$ 个一样的,你的“把所有500个贝壳的组合都试一遍”的策略就彻底破产了,因为组合数是天文数字。

55. 练习 4:P=NP 的推论

📜 [原文9]

练习 4。书中问题 7.18。证明如果 $\mathrm{P}=\mathrm{NP}$,那么除了 $A=\emptyset$ 和 $A=\Sigma^{*}$ 之外,所有 $A \in \mathrm{P}$ 的语言都是 NP 完全的。(提示:考虑 $L \leq_{\mathrm{P}} A$ 的定义,已知 $L \in$ NP 意味着 $L \in \mathrm{P}$。)

这个练习非常适合测试您对 NP 完全性定义的熟悉程度。

假设 $\mathrm{P}=\mathrm{NP}$,并且 $A \in \mathrm{P}$ 是除了 $\emptyset$ 或 $\Sigma^{*}$ 之外的任何语言。这意味着存在两个字符串 $y, z$ 使得 $y \in A$ 且 $z \notin A$。

现在考虑 NP 完全问题 3-SAT,由于假设 $\mathrm{P}=\mathrm{NP}$,我们有 3-SAT $\in P$。因此存在一个多项式时间判定器 $M$ 用于 3-SAT。

我们想证明 $A$ 是 NP 难的。我们将证明 3-SAT $\leq_{\mathrm{P}} A$。所以,我们声称以下是从 3-SAT 到 $A$ 的映射归约。

```

Algorithm 4 A mapping reduction $f$ from 3-SAT to $A$

Input: $\langle\phi\rangle \quad \triangleright \phi$ is a CNF

Run $M$ on $\langle\phi\rangle \quad \triangleright$ This takes polynomial time $\quad \triangleright$ This tells us if $\langle\phi\rangle \in$ 3-SAT or not

if $M$ accepts then

Return $y \quad \triangleright\langle\phi\rangle \in$ 3-SAT, so we return $y \in A$

else

Return $z \quad \triangleright\langle\phi\rangle \notin$ 3-SAT, so we return $z \notin A$

end if

```

很明显,上述映射 $f$ 是在多项式时间内计算的。此外,也很清楚,如果 $\langle\phi\rangle \in$ 3-SAT,我们有 $f(\langle\phi\rangle)=y \in A$。如果 $\langle\phi\rangle \notin$ 3-SAT,那么 $f(\langle\phi\rangle)=z \notin A$。因此 $f(\langle\phi\rangle) \in A \Longleftrightarrow\langle\phi\rangle \in 3$-SAT。

所以这是一个有效的从 3-SAT 到 $A$ 的多项式时间映射归约。

因此 $A$ 是 NP 难的,并且由于 $A \in \mathrm{P}$,$A \in \mathrm{NP}$,因此根据定义 $A$ 是 NP 完全的。

您可能想知道为什么我们需要 $A$ 不是 $\emptyset$ 或 $\Sigma^{*}$。在从语言 $L$ 到 $A$ 的映射归约中,我们需要 $x \in L \Leftrightarrow f(x) \in A$。

但是如果我们将 $A=\emptyset$,那么 $A$ 中就没有字符串!所以如果 $x \in L$,我们永远不能有 $f(x) \in A$。因此如果 $L \neq \emptyset$,就不可能存在从 $L$ 到 $A$ 的映射归约。

类似地,如果 $A=\Sigma^{*}$,那么所有字符串都在 $A$ 中。所以如果 $x \notin L$,我们永远不能有 $f(x) \notin A$。因此如果 $L \neq \Sigma^{*}$,就不可能存在从 $L$ 到 $A$ 的映射归约。

📖 [逐步解释]

这个问题探讨了一个非常反直觉的、但在理论上极为重要的推论:如果 P=NP 这个千古猜想成立,那么整个复杂性世界的版图将会发生惊人的坍塌。具体来说,几乎所有我们认为“简单”的 P 类问题(除了两个最极端的平凡问题),都将在一夜之间变成“最难”的 NP-完全 问题。

证明框架:

  1. 前提假设:
    • P = NP。这意味着所有 NP 问题都可以在多项式时间内被确定性地解决。
    • $A$ 是一个语言,满足:
    • $A \in \mathrm{P}$ (A 是一个“简单”问题)。
    • $A \neq \emptyset$ (A 不是空集,即至少包含一个“是”的实例)。
    • $A \neq \Sigma^*$ (A 不是全集,即至少包含一个“否”的实例)。 $\Sigma^*$ 代表所有可能的字符串集合。
  2. 目标: 证明 $A$ 是 NP-完全的。
  3. NP-完全的定义: 要证明 $A$ 是 NP-完全的,我们需要证明两点:
    • (a) $A \in \mathrm{NP}$
    • (b) $A$ 是 NP-难的 (即,所有 NP 问题都能多项式时间归约到 $A$)。

分步证明:

  • 证明 (a) $A \in \mathrm{NP}$:
  • 我们已知 $A \in \mathrm{P}$。
  • 因为所有可以在多项式时间解决的问题,都可以在多项式时间验证(验证器可以直接自己解决问题,忽略证书),所以 PNP 的一个子集 ($\mathrm{P} \subseteq \mathrm{NP}$)。
  • 因此,从 $A \in \mathrm{P}$ 可以直接推出 $A \in \mathrm{NP}$。这部分证毕。
  • 证明 (b) $A$ 是 NP-难的:
  • 要证明 $A$ 是 NP-难的,我们需要证明对于任意一个 $L \in \mathrm{NP}$,都有 $L \leq_{\mathrm{P}} A$。
  • 一个更便捷的技巧是:我们只需要证明一个已知的 NP-完全 问题可以归约到 $A$ 即可。因为 NP-完全 问题之间可以互相归约,只要 $A$能和它们中的任何一个“搭上关系”,就等于和所有 NP 问题都搭上了关系。
  • 我们选择一个经典的 NP-完全 问题,比如 3-SAT
  • 我们的子目标: 证明 $\text{3-SAT} \leq_{\mathrm{P}} A$。
  • 归约函数构造: 我们需要构造一个多项式时间的函数 $f$,把任意一个 3-SAT 的实例 $\phi$ 映射成 $A$ 的一个实例 $f(\phi)$,并满足 $\phi \in \text{3-SAT} \iff f(\phi) \in A$。

构造归约函数 $f$:

  1. 利用前提:
    • 因为 $A \neq \emptyset$ 且 $A \neq \Sigma^*$,所以必定存在一个字符串 $y$ 使得 $y \in A$,和另一个字符串 $z$ 使得 $z \notin A$。这两个 $y$ 和 $z$ 是固定的。
    • 因为 P = NP,所以 3-SAT 这个问题本身也在 P 中。这意味着存在一个多项式时间的算法(判定器)$M$,可以直接判断任意给定的布尔范式 $\phi$ 是否可满足。
  2. 定义函数 $f(\phi)$:
    • 输入:一个 3-CNF 公式 $\phi$。
    • 算法:
  3. 运行多项式时间3-SAT 判定器 $M$ 在输入 $\phi$ 上。
  4. 如果 $M$ 输出“是”(即 $\phi$ 是可满足的):那么函数 $f$ 就输出我们预先找到的那个固定字符串 $y$。
  5. 如果 $M$ 输出“否”(即 $\phi$ 是不可满足的):那么函数 $f$ 就输出我们预先找到的那个固定字符串 $z$。
  6. 验证函数 $f$ 的有效性:
    • $f$ 是多项式时间的吗? 是。因为 $f$ 的主体操作就是运行算法 $M$,而我们知道 $M$ 是多项式时间的。找到 $y$ 和 $z$ 是一个一次性的预备工作,不计入每次调用的时间。输出 $y$ 或 $z$ 也是常数时间
    • $f$ 满足归约条件吗? 我们需要检查 $\phi \in \text{3-SAT} \iff f(\phi) \in A$。
    • 正向: 如果 $\phi \in \text{3-SAT}$,那么 $M$ 会接受,我们的 $f$ 会输出 $y$。因为我们选择的 $y$ 满足 $y \in A$,所以 $f(\phi) \in A$。条件满足。
    • 反向: 如果 $f(\phi) \in A$,那么 $f$ 输出的结果必须是 $y$(因为 $z \notin A$)。而 $f$ 只在 $M$ 接受 $\phi$ 时才输出 $y$。$M$ 接受 $\phi$ 意味着 $\phi \in \text{3-SAT}$。条件满足。
    • 归约条件成立!
  7. 最终结论:
    • 我们成功证明了 $\text{3-SAT} \leq_{\mathrm{P}} A$。这意味着 $A$ 是 NP-难的。
    • 结合我们之前证明的 $A \in \mathrm{NP}$,根据定义,$A$ 是 NP-完全的。

关于平凡语言 $\emptyset$ 和 $\Sigma^*$ 的解释:

  • 为什么 $A$ 不能是 $\emptyset$?
  • 如果 $A=\emptyset$(空集),那么任何字符串都不在 $A$ 中,即 $f(x) \in A$ 永远为假。
  • 归约条件是 $x \in L \iff f(x) \in A$。如果 $L$ 不是空集(比如 3-SAT 就不是),那么总存在某个 $x \in L$。对于这个 $x$,左边为真,右边为假,矛盾。所以无法构造出这样的归约。
  • 为什么 $A$ 不能是 $\Sigma^*$?
  • 如果 $A=\Sigma^*$(全集),那么任何字符串都在 $A$ 中,即 $f(x) \in A$ 永远为真。
  • 如果 $L$ 不是全集(比如 3-SAT),那么总存在某个 $x \notin L$。对于这个 $x$,左边为假,右边为真,矛盾。也无法构造出归约。
  • 这两个平凡语言无法作为归约的目标,因为它们无法区分“是”与“否”两种情况,失去了作为“逻辑门”的能力。
∑ [公式拆解]
  • $\mathrm{P}=\mathrm{NP}$: 一个核心假设,意味着解决一个 NP 问题和验证一个 NP 问题的解,难度是相同的(都在多项式时间内)。
  • $\emptyset$: 空集。
  • $\Sigma^*$: 所有可能字符串的集合。
  • $f: \Sigma^* \to \Sigma^*$: 一个映射函数,将一个语言的实例映射到另一个语言的实例。
  • $L \leq_{\mathrm{P}} A$: 语言 $L$ 可以多项式时间归约到语言 $A$。
💡 [数值示例]
  • 假设 $\mathrm{P}=\mathrm{NP}$ 成立。
  • 令 $A$ 为 EVENLENGTH 问题:判断一个二进制字符串的长度是否为偶数。
  • 显然 EVENLENGTH $\in \mathrm{P}$。
  • EVENLENGTH $\neq \emptyset$ (e.g., "10" $\in$ A)。
  • EVENLENGTH $\neq \Sigma^*$ (e.g., "101" $\notin$ A)。
  • 我们的目标是证明 EVENLENGTHNP-完全的。
  • 构造归约函数 $f$ 从 3-SATEVENLENGTH:
  • 预备:找到 $y \in A$, $z \notin A$。我们选 $y=$ "00", $z=$ "0"。
  • 存在一个多项式时间的 3-SAT 求解器 $M$。
  • 定义 $f(\phi)$:
  • 如果 $M(\phi)$ 接受,返回 "00"。
  • 如果 $M(\phi)$ 拒绝,返回 "0"。
  • 验证:
  • $\phi$ 可满足 $\iff M(\phi)$ 接受 $\iff f(\phi) = \text{"00"}$
  • $f(\phi) \in \text{EVENLENGTH} \iff f(\phi) = \text{"00"}$
  • 因此,$\phi$ 可满足 $\iff f(\phi) \in \text{EVENLENGTH}$。
  • 归约成功。这意味着连“判断字符串长度是奇是偶”这么简单的问题,都变成了 NP-完全 问题。
⚠️ [易错点]
  1. 对 P=NP 的影响感到困惑: P=NP 是一个非常强的假设,它赋予了我们一个“魔法”能力——在多项式时间内解决任何 NP 问题。证明中的判定器 $M$ 就是这个魔法的具体体现。
  2. 归约方向: 归约的方向是 $\text{3-SAT} \leq_{\mathrm{P}} A$,即把难问题归约到(看似)简单的问题。这是证明 $A$ 是 NP-难的标准方法。
  3. $y$ 和 $z$ 的选择: $y$ 和 $z$ 可以是任何满足条件的字符串。它们的选择不影响证明的逻辑。
📝 [总结]

P=NP 的假设下,任何一个非平凡的 P 类语言 $A$ 都变成了 NP-完全问题。证明的关键是构造一个从已知 NP-完全问题(如 3-SAT)到 $A$ 的多项式时间归约。这个归约函数利用了 P=NP 带来的“魔法”:一个多项式时间的 3-SAT 求解器。该求解器预先判断输入实例的真伪,然后巧妙地将结果映射到 $A$ 中的一个“是”实例或一个“否”实例,从而完成归约。

🎯 [存在目的]

此题旨在展示 P=NP 猜想的深刻含义。如果它为真,不仅仅意味着我们能高效解决旅行商等难题,更意味着整个复杂性等级结构会发生坍塌,PNP-Complete 这两个看似遥远的类别会惊人地重合在一起。这揭示了复杂性理论内部结构之间的紧密联系。

🧠 [直觉心智模型]
  1. 假设“瞬间致富”($\mathrm{P}=\mathrm{NP}$)的方法被发现了。
  2. $A$ 是一个简单的任务,比如“判断硬币是正面还是反面”。
  3. 3-SAT 是一个超级复杂的商业决策。
  4. 你可以构造一个“投资顾问” $f$。客户给你一个商业决策 $\phi$,你用“瞬间致富”法立刻判断出这个决策是赚钱还是亏钱。
  5. 如果赚钱,你就告诉客户“硬币是正面”(输出 $y \in A$)。
  6. 如果亏钱,你就告诉客户“硬币是反面”(输出 $z \notin A$)。
  7. 于是,“判断商业决策”这个难题,就被你转换成了“判断硬币正反面”。这意味着,“判断硬币正反面”这个简单任务,和那个超级商业决策一样“有价值”(一样“难”)。
💭 [直观想象]

想象你有一个“全知按钮” $M$ (因为 $\mathrm{P}=\mathrm{NP}$),你问它任何 3-SAT 问题 $\phi$,它都会立刻告诉你“真”或“假”。

现在你想证明“判断一个数是否为偶数”($A$) 是宇宙中最难的问题之一。

你建立一个服务亭 $f$:

  1. 任何人都可以来问你一个 3-SAT 问题 $\phi$。
  2. 你偷偷按下“全知按钮” $M$。
  3. 如果按钮说“真”,你就告诉来人:“答案是 2”(一个偶数,$y \in A$)。
  4. 如果按钮说“假”,你就告诉来人:“答案是 1”(一个奇数,$z \notin A$)。
  5. 于是,别人问你的任何 3-SAT 难题,都被你转化为了一个关于奇偶性的回答。这间接证明了,你用来回答的“奇偶性”问题,蕴含了解决 3-SAT 难题的能力,因此它和 3-SAT 一样难。

66. 练习 5:简单路径问题 SPATH 与 LPATH

6.1. 短路径问题 SPATH 属于 P

📜 [原文10]

练习 5。书中问题 7.21。设 $G$ 表示一个无向图。并且设

  • SPATH $=\{\langle G, a, b, k\rangle-G$ 包含一条从 $a$ 到 $b$ 长度至多为 $k$ 的简单路径 $\}$
  • $\mathrm{LPATH}=\{\langle G, a, b, k\rangle-G$ 包含一条从 $a$ 到 $b$ 长度至少为 $k$ 的简单路径 $\}$

证明 SPATH $\in \mathrm{P}$ 且 LPATH 是 NP 完全的。(简单路径是不访问同一个节点两次的路径。)

回想一下,简单路径是永不访问同一个节点两次的路径(即,路径没有)。

我们首先证明 SPATH $\in P$。要检查从 $a$ 到 $b$ 是否存在长度 $\leq k$ 的简单路径,只需执行以下操作:从 $G$ 中的 $a$ 开始执行广度优先搜索

当我们执行广度优先搜索(BFS)时,我们首先看到所有距离 $a$ 为 1 的节点,然后是距离为 2 的节点,依此类推……所以如果我们在距离达到 $k+1$ 之前到达 $b$,我们就接受,否则就拒绝。显然,执行 BFS 所需时间是输入大小的多项式

📖 [逐步解释]

这个问题展示了一对看似“镜像”的问题,但它们的复杂性却有天壤之别。SPATH (Shortest Path) 寻找短路径,而 LPATH (Longest Path) 寻找长路径。

第一部分:证明 SPATH $\in \mathrm{P}$

问题定义:

  • SPATH: 给定图 $G$,起点 $a$,终点 $b$,和一个整数 $k$。问是否存在一条从 $a$ 到 $b$ 的简单路径,其长度(边的数量)至多为 $k$?

关键洞察:

  • 如果存在一条从 $a$ 到 $b$ 长度不大于 $k$ 的路径,那么最短的那条路径的长度也必然不大于 $k$。
  • 广度优先搜索 (BFS) 是一个寻找图中两点间最短路径(以边的数量衡量)的经典算法。
  • BFS 找到的路径天然就是简单路径,因为它按层次扩展,不会走回头路形成环。

算法:

  1. 在图 $G$ 上,从源点 $a$ 开始执行 BFS
  2. BFS 会维护每个节点到 $a$ 的最短距离。我们用一个数组 dist[] 来记录,初始时 dist[a]=0,其他为无穷大。
  3. BFS 逐层扩展。首先访问所有 dist=1 的节点,然后是 dist=2 的节点,以此类推。
  4. BFS 执行过程中,一旦我们第一次到达节点 $b$,此时记录的 dist[b] 就是从 $a$ 到 $b$ 的最短路径长度。
  5. 我们可以修改 BFS
    • 如果在搜索过程中计算出的 dist[b] 小于或等于 $k$,那么我们已经找到了一条满足条件的路径。算法可以立即停止并返回“是”。
    • 如果 BFS 正常结束(即所有从 $a$ 可达的节点都已访问)而我们从未到达 $b$,或者到达 $b$ 时其最短距离 dist[b] 已经大于 $k$,那么就不存在这样的短路径。
    • 一个更简单的实现是:完整运行 BFS 得到从 $a$ 到所有点的最短距离。然后检查 dist[b] 的值。如果 dist[b] <= k,则返回“是”,否则返回“否”。

时间复杂性分析:

  • BFS 算法的运行时间对于一个有 $V$ 个顶点和 $E$ 条边的图是 $O(V+E)$。
  • 输入大小是图的描述(邻接矩阵 $O(V^2)$ 或邻接表 $O(V+E)$)加上 $a,b,k$。
  • $O(V+E)$ 是输入大小的多项式(甚至是线性的)。
  • 因此,SPATH 问题可以在多项式时间内解决,故 SPATH $\in \mathrm{P}$。
∑ [公式拆解]
  • SPATH: $\{\langle G, a, b, k\rangle \mid \exists \text{ simple path } p \text{ from } a \text{ to } b \text{ with length}(p) \le k \}$
  • BFS (Breadth-First Search): 一种图遍历算法。
  • 性质: BFS 找到的从源点 $s$ 到任何其他顶点 $v$ 的路径,是边数最少的路径。
  • 时间复杂度: $T_{BFS} = O(|V| + |E|)$,其中 $|V|$ 是顶点数,$|E|$ 是边数。
  • 结论: 存在一个解决 SPATH 的算法 (BFS),其运行时间是输入的多项式,所以 SPATH $\in \mathrm{P}$。
💡 [数值示例]
  • 示例:
  • 图 $G$ 有节点 {a, c, d, b, e}。边为 (a,c), (c,d), (a,d), (d,b), (d,e), (e,b)。
  • 问题: $\langle G, a, b, k=2 \rangle$ 是否在 SPATH 中?
  • 算法执行:
  1. 从 $a$ 开始 BFS。dist[a]=0。队列 Q = {a}。
  2. 取出 $a$。其邻居是 $c, d$。dist[c]=1, dist[d]=1。Q = {c, d}。
  3. 取出 $c$。其未访问邻居为空。Q = {d}。
  4. 取出 $d$。其邻居是 $b, e$。dist[b]=2, dist[e]=2。Q = {b, e}。
  5. 此时我们已经到达了 $b$,并且计算出 dist[b]=2
    • 判断:
    • 我们找到了从 $a$到$b$ 的最短路径 $a \to d \to b$,长度为 2。
    • 因为 $2 \le k=2$,所以答案是“是”。
  • 如果 $k=1$:
  • 算法找到的最短路是 2。因为 $2 \not\le 1$,所以答案是“否”。
⚠️ [易错点]
  1. 简单路径 vs. 普通路径: 在这个问题中,最短路径天然是简单路径。但对于 LPATH,这个区别至关重要。一条最长的 非简单 路径可能无限长(如果图中有环)。
  2. BFS vs. DFS: 如果错误地使用深度优先搜索 (DFS),它找到的第一条路径不保证是短的,所以不能直接用于解决 SPATH。
  3. Dijkstra/Bellman-Ford: 如果边有权重,就需要用 Dijkstra (非负权) 或 Bellman-Ford (可有负权) 算法。对于无权图,BFS 就是最高效的。
📝 [总结]

SPATH 问题可以在多项式时间内解决,因为它等价于寻找图中两点间的最短路径长度是否超过一个阈值。使用标准的广度优先搜索 (BFS) 算法即可在 $O(V+E)$ 的时间内找到最短路径,这是一个多项式时间算法,因此 SPATH $\in \mathrm{P}$。

🎯 [存在目的]

这部分的存在是为了与下一部分 LPATH 的 NP-完全性形成强烈对比。它展示了“至多 k”和“至少 k”这两个看似微小的词语差异,如何导致问题复杂性从“简单”(P) 变为“困难”(NP-完全)。

🧠 [直觉心智模型]
  1. SPATH: 你在地图上找从家到超市不超过2公里的路。你很自然地会去找那条最短的路,如果最短的路都超过2公里了,那肯定没有别的更短的路了。找最短路是一个很直接、有高效方法的任务。
💭 [直观想象]
  1. SPATH: 想象水波。从起点 $a$ 滴一滴水,水波(BFS的层次)一圈一圈地向外扩散。第一圈是距离1,第二圈是距离2... 我们只要看终点 $b$ 是在哪一圈被水波接触到的。如果是在第 $k$ 圈或更早,答案就是“是”。这是一个非常自然的、物理过程可模拟的高效搜索。

6.2. 长路径问题 LPATH 是 NP-完全的

📜 [原文11]

我们现在证明 LPATH 是 NP 完全的。

首先,我们证明 LPATH 在 NP 中。这是一个 LPATH 的验证器:

```

Algorithm 5 A verifier for LPATH

Input: < G,a,b,k>,p \triangleright p is the extra string the verifier takes as input

Check p is a simple path from a to b in G.

Check that p has length at least k.

if Both of the above are true then

Accept.

else

Reject.

end if

```

显然,上述程序在多项式时间内运行。也很清楚,如果 $\langle G, a, b, k\rangle \in \mathrm{LPATH}$,那么从 $a$ 到 $b$ 必定存在一条长度 $\geq k$ 的简单路径。所以只需将 $p$ 设为这条路径,这将导致验证器接受。显然,如果不存在这样的路径,就没有 $p$ 会导致验证器接受 $\langle G, a, b, k\rangle, p$。

所以剩下要证明的是问题是 NP 难的。为此,我们将 NP 完全问题 HamPath 归约到 LPATH。我们需要给出一个从 HamPath 到 LPATH 的多项式时间映射归约。

回想一下,HamPath 是以下问题:给定一个图 $G$ 和两个节点 $s, t$,是否存在一条从 $s$ 到 $t$ 的哈密顿路径

给定 $G, s, t$ 作为 HamPath 的输入,我们的函数输出 $\langle G, a=s, b=t, k=n\rangle$。即 $f(\langle G, s, t\rangle)= \langle G, s, t, n\rangle$。

显然这可以在多项式时间内计算。所以剩下要证明的是 $\langle G, s, t\rangle \in$ HamPath 当且仅当 $\langle G, s, t, n\rangle \in \mathrm{LPATH}$。

这并不难,一旦我们展开哈密顿路径的定义。根据定义,存在一条从 $s$ 到 $t$ 的哈密顿路径,当且仅当存在一条从 $s$ 到 $t$ 的简单路径,它访问每个顶点一次。

由于路径从 $s$ 开始,在 $t$ 结束,并经过所有 $n$ 个顶点一次,这意味着它的长度必须是 $n$⁴。

因此,根据定义,当且仅当存在一条从 $s$ 到 $t$ 长度为 $n$ 的简单路径时,$G$ 才具有从 $s$ 到 $t$ 的哈密顿路径

还要注意简单路径的长度不能超过 $n$,否则会重复一个顶点,因此就不是简单路径

因此,我们清楚地知道,当且仅当存在一条从 $s$ 到 $t$ 长度至少为 $n$ 的简单路径时,才存在从 $s$ 到 $t$ 的哈密顿路径

所以 $\langle G, s, t\rangle \in$ HamPath 当且仅当 $\langle G, s, t, n\rangle \in \mathrm{LPATH}$。这证明了 HamPath $\leq_{\mathrm{P}}$ LPATH。因此 LPATH 是 NP 难的。

由于 LPATH 是 NP 难的且在 NP 中,它是 NP 完全的。

📖 [逐步解释]

第二部分:证明 LPATH 是 NP-完全的

要证明 LPATH 是 NP-完全的,我们需要做两件事:

  1. 证明 LPATH $\in \mathrm{NP}$。
  2. 证明 LPATH 是 NP-难的。

1. 证明 LPATH $\in \mathrm{NP}$

  • 思路: 我们需要为 LPATH 设计一个多项式时间的验证器。
  • 证书: 一个合理的证书 $p$ 就是一条宣称满足条件的路径,即一个顶点的序列。
  • 验证器算法 (Algorithm 5):
  • 输入: $\langle G, a, b, k \rangle$ 和证书(路径)$p$。
  • 步骤1: 检查 $p$ 是否是一条从 $a$到$b$ 的简单路径
  • 检查路径的起点是否是 $a$,终点是否是 $b$。($O(1)$)
  • 检查路径中没有重复的顶点。(用哈希表或排序,可在路径长度的多项式时间内完成)。
  • 检查路径中每一步相邻的两个顶点在图 $G$ 中是否真的有边相连。($O(|p|)$ 次查询)。
  • 步骤2: 检查路径 $p$ 的长度是否至少为 $k$。路径长度是顶点数减1,即 $|p|-1 \ge k$。($O(|p|)$)。
  • 结论: 如果上述检查都通过,则接受;否则拒绝。
  • 时间分析: 路径 $p$ 作为简单路径,其长度最多为 $n-1$($n$是顶点数)。所有检查步骤都可以在图和路径大小的多项式时间内完成。因此,验证器是多项式时间的。
  • 正确性: 如果存在这样一条长路径,那么这条路径本身就是最好的证书。如果不存在,任何给定的路径都无法通过验证。
  • 结论: LPATH 属于 NP

2. 证明 LPATH 是 NP-难的

  • 思路: 我们需要把一个已知的 NP-完全问题多项式时间归约到 LPATH。一个和路径问题高度相关的 NP-完全问题是哈密顿路径 (HamPath)
  • 归约目标: 证明 HamPath $\leq_{\mathrm{P}}$ LPATH。
  • HamPath 问题定义: 给定图 $G$ 和两个顶点 $s, t$,问是否存在一条从 $s$ 到 $t$ 的简单路径恰好访问图中每个顶点一次
  • 构造归约函数 $f$:
  • $f$ 的输入: 一个 HamPath 问题的实例 $\langle G=(V,E), s, t \rangle$。设 $|V|=n$。
  • $f$ 的输出: 一个 LPATH 问题的实例 $\langle G', a, b, k \rangle$。
  • 我们的构造非常直接:
  • $G' = G$ (图保持不变)
  • $a = s$ (起点保持不变)
  • $b = t$ (终点保持不变)
  • $k = n-1$ (设置目标路径长度为 $n-1$)
  • 于是,$f(\langle G, s, t \rangle) = \langle G, s, t, n-1 \rangle$。(原文中用 $k=n$ 假设路径长度为顶点数,这里按边数算为 $n-1$,两者等价)。
  • 验证归约:
  • $f$ 是多项式时间的吗? 是。这个函数只是复制了图和起终点,并将 $k$ 设置为 $n-1$。计算 $n$ 并输出,这些都是非常快速的操作。
  • 满足归约条件吗? 我们需要证明 $\langle G, s, t \rangle \in \text{HamPath} \iff \langle G, s, t, n-1 \rangle \in \text{LPATH}$。
  • ($\Rightarrow$) 正向: 假设 $G$ 中存在一条从 $s$ 到 $t$ 的哈密顿路径。
  • 根据哈密顿路径的定义,这是一条访问了全部 $n$ 个顶点的简单路径
  • 一条包含 $n$ 个不同顶点的路径,其边的数量恰好是 $n-1$。
  • 所以,我们找到了一条从 $s$ 到 $t$ 的简单路径,其长度为 $n-1$。
  • 这条路径的长度满足“至少为 $n-1$”的要求。
  • 因此,$\langle G, s, t, n-1 \rangle \in \text{LPATH}$。
  • ($\Leftarrow$) 反向: 假设 $\langle G, s, t, n-1 \rangle \in \text{LPATH}$。
  • 这意味着,在图 $G$ 中,存在一条从 $s$ 到 $t$ 的简单路径,其长度至少为 $n-1$。
  • 一条简单路径不能有重复顶点。在一个只有 $n$ 个顶点的图中,一条简单路径最多只能包含 $n$ 个顶点,其长度最大为 $n-1$。
  • 所以,“长度至少为 $n-1$” 和 “长度最大为 $n-1$” 结合起来,意味着这条路径的长度必须 恰好是 $n-1$。
  • 一条长度为 $n-1$ 的简单路径必然访问了 $n$ 个不同的顶点。
  • 在一个只有 $n$ 个顶点的图中,这意味着它访问了 所有 顶点。
  • 这完全符合哈密顿路径的定义。
  • 因此,$\langle G, s, t \rangle \in \text{HamPath}$。
  • 结论: 归约有效。我们证明了 HamPath $\leq_{\mathrm{P}}$ LPATH。因为 HamPath 是 NP-完全的,所以 LPATH 至少和它一样难,故 LPATH 是 NP-难的。

最终结论:

  • 因为 LPATH $\in \mathrm{NP}$ 并且 LPATH 是 NP-难的,所以根据定义,LPATH 是 NP-完全的。
∑ [公式拆解]
  • LPATH: $\{\langle G, a, b, k\rangle \mid \exists \text{ simple path } p \text{ from } a \text{ to } b \text{ with length}(p) \ge k \}$
  • HamPath: $\{\langle G, s, t\rangle \mid \exists \text{ simple path } p \text{ from } s \text{ to } t \text{ that visits every vertex in } G \text{ exactly once} \}$
  • 路径长度: 原文注脚4将路径长度定义为顶点数,通常我们定义为边数。如果路径有 $m$ 个顶点,就有 $m-1$ 条边。证明逻辑在这两种定义下都成立。
  • 哈密顿路径访问 $n$ 个顶点 $\implies$ 长度为 $n-1$ 条边。
  • 归约等价性:

$\langle G, s, t \rangle \in \text{HamPath}$

$\iff$ 存在从 $s$ 到 $t$ 的简单路径,访问了 $n$ 个顶点。

$\iff$ 存在从 $s$ 到 $t$ 的简单路径,长度为 $n-1$。

$\iff$ 存在从 $s$ 到 $t$ 的简单路径,长度至少为 $n-1$ (因为最长也就是 $n-1$)。

$\iff \langle G, s, t, n-1 \rangle \in \text{LPATH}$

💡 [数值示例]
  • 归约示例:
  • 假设有一个 HamPath 实例:图 $G$ 有4个顶点 {s, u, v, t},边为 (s,u), (u,v), (v,t), (s,t)。问 $\langle G, s, t \rangle$ 是否有哈密顿路径?
  • 归约函数 $f$ 将其转换为 LPATH 实例:$\langle G, s, t, k=3 \rangle$。
  • 现在解决这个 LPATH 问题:$G$ 中是否存在从 $s$ 到 $t$ 长度至少为3的简单路径
  • 我们可以找到路径 $s \to u \to v \to t$,它是一条简单路径,访问了4个顶点,长度为3。
  • $3 \ge k=3$,所以 LPATH 实例的答案是“是”。
  • 这对应于 HamPath 实例的答案也是“是”。
⚠️ [易错点]
  1. 为何不能用 BFS/Dijkstra 找最长路? 这些基于“最优子结构”和“贪心选择”的算法失效了。一条通往最长路上的子路径,并不一定本身是它起点到终点的最长子路径。例如,为了绕远路,你可能需要先走一条看起来很“亏”的短路,以便后续能接上一大段路。这种需要全局视野、无法局部优化的特性,是许多 NP-完全 问题的共同点。
  2. 简单路径的约束: 如果问题不要求简单路径,而图中有正权重的环,那么最长路可以无限长,问题变得没有意义。简单路径这个约束是核心。
📝 [总结]

LPATH 是 NP-完全的。首先,通过给出一个路径作为证书,我们可以在多项式时间内验证它是否是满足条件的简单路径,证明了 LPATH $\in \mathrm{NP}$。然后,通过一个从已知的 NP-完全问题——哈密顿路径 (HamPath)——到 LPATH 的多项式时间归约,证明了 LPATH 是 NP-难的。归约的核心思想是,一个 $n$ 顶点的图中的哈密顿路径,本质上就是一条长度恰好为 $n-1$ 的简单路径,这恰好可以被 LPATH 问题中“长度至少为 $n-1$”的条件所捕获。

🎯 [存在目的]

此题是复杂性理论中一个经典的例子,用来说明微小的问题陈述变化可以导致复杂性的巨大差异。它教育学生如何通过归约来证明一个新问题是 NP-难的,这是解决复杂性问题的一项核心技能。

🧠 [直觉心智模型]
  1. LPATH: 你在地图上找从家到超市 至少 10公里的路,并且不能走重复的路口。这变成了一个难题。你不能再贪心地走最短路了,你需要有策略地“绕远”。但你怎么知道你选的绕路方案是所有方案里最长的之一呢?你可能需要尝试所有可能的路径组合,这是一个组合爆炸的问题。
💭 [直观想象]
  1. LPATH: 想象你在一个巨大的迷宫里,要找一条从入口到出口的最长路径,且不走回头路。你每走到一个岔路口,都面临选择。你不知道哪个选择最终能带你走上最长的旅程。你可能需要探索所有可能的路径才能确定。这和水波扩散(BFS)那种简单明了的过程完全不同,充满了不确定性和需要回溯的探索。这正是 NP-完全 问题的“感觉”。

77. 脚注解释

7.1. 脚注 1

📜 [原文12]

[^0]: ${ }^{1}$ 但这意味着如果 $x \in L$,则存在一个长度为 $|x|$ 的多项式的 $c$,使得 $V(x, c)$ 接受。否则,$V$ 将没有时间在多项式时间内读取 $c$。

📖 [逐步解释]

这个脚注是对练习1中问题2答案的补充说明,它解释了为什么 NP 定义中“验证器 $V$ 运行时间是 $|x|$ 的多项式”这一条,隐含地要求了“证书 $c$ 的长度也必须是 $|x|$ 的多项式”。

逻辑链条:

  1. 前提: 验证器 $V$ 的运行时间是 $T_V = O(|x|^k)$,其中 $k$ 是常数
  2. 图灵机的工作方式: 一个图灵机要处理输入,必须先在带子上读取它。读取一个长度为 $m$ 的输入,至少需要 $m$ 步操作(磁头需要移动 $m$ 个位置)。
  3. $V$ 的输入: 验证器 $V$ 的总输入是字符串 $x$ 和证书 $c$,总长度是 $|x| + |c|$。
  4. 时间下限: 要完整读取其输入, $V$ 至少需要 $O(|x| + |c|)$ 的时间。
  5. 结合: 我们有 $V$ 的运行时间必须同时满足两个条件:
    • $T_V \ge O(|x| + |c|)$ (因为要读取输入)
    • $T_V = O(|x|^k)$ (根据 NP 的定义)
  6. 推论: 将两者结合,我们得到 $O(|x| + |c|) \le O(|x|^k)$。
  7. 结论: 为了使这个不等式成立, $|c|$ 的大小不能超过 $|x|$ 的多项式。如果 $|c|$ 是指数级的,比如 $2^{|x|}$,那么左边就是指数级的,右边是多项式级的,不等式将不成立。所以,必然存在某个多项式 $p$ 使得 $|c| \le p(|x|)$。
📝 [总结]

该脚注强调了 NP 验证器的多项式时间限制是一个硬约束,它不仅限制了计算步骤,也通过物理限制(读取时间)间接限制了能够提供给验证器的信息量(证书长度)。

7.2. 脚注 2

📜 [原文13]

[^1]: ${ }^{2}$ 这是一个您可以忽略的技术点。我们应该首先检查 $c$ 不会太大。我的意思是 $|c|=O\left(n^{k}\right)$,其中 $V_{1}, V_{2}$ 都以 $O\left(n^{k}\right)$ 的时间运行。也就是说,如果 $c$ 大于 $V_{1}$ 和 $V_{2}$ 的运行时间,我们应该拒绝。这是为了避免 $c$ 太大导致将其作为输入给 $V_{1}$ 需要太长时间的情况。如果 $c$ 大于 $V_{1}, V_{2}$ 的运行时间,我们知道它们永远不会接受 $(x, c)$。

📖 [逐步解释]

这个脚注是针对练习2(证明 NP 对并集封闭)中构造的新验证器 $V$ 的一个技术性补充。它处理了一个微妙的边界情况。

问题: 在我们为 $L_1 \cup L_2$ 构造的验证器 $V$ 中,我们假设 $V_1$ 和 $V_2$ 的运行时间分别是 $p_1(|x|)$ 和 $p_2(|x|)$。根据上一条脚注的逻辑,它们各自的有效证书 $c_1, c_2$ 的长度也分别被 $p_1(|x|)$ 和 $p_2(|x|)$ 所限制。那么,我们给新验证器 $V$ 的证书 $c$ 的长度应该是什么呢?

脚注的观点:

  1. 我们知道 $V_1$ 的运行时间是某个多项式 $p_1(|x|)$, $V_2$ 的运行时间是 $p_2(|x|)$。
  2. 如果提供给 $V_1$ 的证书 $c$ 的长度 $|c|$ 大于 $p_1(|x|)$,那么 $V_1$ 甚至没有足够的时间来读完整个证书,它绝对不可能接受。同样的情况也适用于 $V_2$。
  3. 因此,在我们构造的验证器 $V(x, c)$ 中,可以增加一个初始步骤:检查证书 $c$ 的长度。
    • 设 $p_{max}(|x|) = \max(p_1(|x|), p_2(|x|))$。
    • 如果 $|c| > p_{max}(|x|)$,那么这个 $c$ 不可能是 $V_1$ 或 $V_2$ 的有效证书,我们可以让 $V$ 直接拒绝,而无需实际运行 $V_1$ 或 $V_2$。
  4. 这个预检查步骤确保了传递给 $V_1$ 和 $V_2$ 的证书长度是有界的,从而使整个时间分析更加严谨。它明确了新验证器 $V$ 的有效证书长度也被一个多项式所限制,即 $p_{max}(|x|)$。

为什么可以忽略:

作者说这是“可以忽略的技术点”,因为 NP 的定义是“存在一个证书”。我们证明了如果 $x \in L_1 \cup L_2$,那么就存在一个(长度为多项式的)证书 $c_1$ 或 $c_2$ 能让 $V$ 接受。对于那些过长的、无效的证书,我们的验证器 $V$ 将会(正确地)拒绝它们,这并不影响证明的核心逻辑。这个脚注只是让验证器的构造更加“鲁棒”和“高效”。

📝 [总结]

该脚注为练习2中的构造性证明增加了一个技术细节:新的验证器可以首先检查证书的长度,如果长度超过了两个子验证器可能处理的范围,就直接拒绝。这可以形式上保证新验证器的证书长度也是多项式有界的。

7.3. 脚注 3

📜 [原文14]

[^2]: ${ }^{3}$.重要的是要认识到我们查看的是最坏情况输入的运行时间。在这里,只要您给出 $k=n / 2$(或 $n$ 的任何足够大的函数),算法就会非常慢。

📖 [逐步解释]

这个脚注是对练习3中关于通用 Clique 问题分析的强调。

核心思想:

  1. 复杂性分析是悲观的: 在分析一个算法的复杂性时,我们通常关心的是最坏情况 (Worst-Case)。这意味着我们要找到一种输入,能让算法运行得最慢,并以此作为其性能的度量。
  2. 在 Clique 问题中什么是“最坏情况”: 对于暴力枚举算法 $O(\binom{n}{k}k^2)$,其运行时间主要由组合数 $\binom{n}{k}$ 决定。
  3. $\binom{n}{k}$ 的性质: 对于固定的 $n$,当 $k$ 在 $n/2$ 附近时,$\binom{n}{k}$ 的值最大。当 $k$ 接近 0 或 $n$ 时,$\binom{n}{k}$ 的值很小。
  4. 构造最坏输入: 因此,要让算法变得“非常慢”,我们只需要选择一个 $k$ 值,它是 $n$ 的一个线性函数,比如 $k=n/2$ 或者 $k=n/3$。只要 $k$ 不是常数,并且能随 $n$ 增长,算法的指数特性就会暴露出来。
  5. 结论: 哪怕算法对于某些输入(比如 $k=2$)很快,但只要存在一类系统性的输入(比如 $k=n/2$)能让它变得指数慢,这个算法就不是多项式时间算法。
📝 [总结]

该脚注强调了在判断算法是否为多项式时间时,必须考虑最坏情况的输入。对于通用 Clique 问题,当 $k$ 作为 $n$ 的一个函数(如 $k=n/2$)时,暴力算法的运行时间呈现指数增长,因此它不是一个多项式时间算法。

7.4. 脚注 4

📜 [原文15]

[^3]: ${ }^{4}$ 这里我将路径的长度计为顶点数

📖 [逐步解释]

这个脚注是作者在练习5证明 LPATH 的 NP-难度时,对自己使用的“路径长度”定义的一个澄清。

两种常见的“路径长度”定义:

  1. 边数 (Edge Count): 一条路径经过的边的数量。这是图论中最常见的定义。一条从 $v_0$到$v_m$的路径 $v_0 \to v_1 \to \dots \to v_m$ 长度为 $m$。
  2. 顶点数 (Vertex Count): 一条路径包含的顶点的数量。在同样路径下,长度为 $m+1$。

脚注的作用:

  • 在证明 LPATH 是 NP-难 时,作者将 HamPath 归约到 LPATH,并将 LPATH 的参数 $k$ 设置为 $n$(图中顶点的总数)。
  • 他这么做的依据是,他把“路径长度”暂时定义为了“路径上的顶点数”。
  • 根据这个定义:
  • 哈密顿路径:访问所有 $n$ 个顶点的路径 $\implies$ 长度为 $n$。
  • LPATH 问题:寻找长度至少为 $k$ 的路径。
  • 设置 $k=n$ 后,LPATH 问题就变成了“寻找长度至少为 $n$ 的简单路径”。
  • 在一个 $n$ 顶点的图中,简单路径最长就是 $n$(访问所有顶点)。
  • 所以“长度至少为 $n$”就等价于“长度恰好为 $n$”,这正好就是哈密顿路径。

与标准定义的关系:

  • 如果使用标准的“边数”定义:
  • 哈密顿路径:访问 $n$ 个顶点 $\implies$ 长度为 $n-1$ 条边。
  • 归约时应设置 $k=n-1$。
  • LPATH 问题变成“寻找长度至少为 $n-1$ 的简单路径”。
  • 简单路径最长为 $n-1$ 条边。
  • 所以“长度至少为 $n-1$”等价于“长度恰好为 $n-1$”,这也正好是哈密顿路径。

结论:

这个脚注澄清了作者在特定步骤中使用了一个非标准的定义,但它想强调的是,无论使用哪种定义,证明的逻辑都是完全相同的,只是具体的 $k$ 值差了1。这不影响归约的正确性。

📝 [总结]

该脚注澄清了作者在证明中使用的“路径长度”是指顶点数,而非更常用的边数。这是一个定义上的选择,两种定义都能得出相同的结论,即 HamPath 可以归约到 LPATH。

8行间公式索引

1. $x \in L_{1} \Leftrightarrow \exists c_{1} \text { such that } V_{1}\left(x, c_{1}\right) \text { accepts. }$

- 解释: 这是语言 $L_1$ 属于NP类的形式化定义,说明一个字符串 $x$ 在 $L_1$ 中,当且仅当存在一个证书 $c_1$ 能被 $L_1$ 的验证器 $V_1$ 所接受。

2. $x \in L_{2} \Leftrightarrow \exists c_{2} \text { such that } V_{2}\left(x, c_{2}\right) \text { accepts. }$

- 解释: 这是语言 $L_2$ 属于NP类的形式化定义,与上一条类似。

3. $x \in L_{1} \cup L_{2} \Longleftrightarrow \exists c \text { such that } V(x, c) \text { accepts. }$

- 解释: 这是证明 $L_1 \cup L_2$ 属于NP需要达成的目标,即为 $L_1 \cup L_2$ 找到一个满足NP定义的验证器 $V$。

4. $x \in L_{1} \cup L_{2} \Rightarrow \exists c \text { such that } V(x, c) \text { accepts }$

- 解释: 这是证明 $L_1 \cup L_2 \in \mathrm{NP}$ 的完备性部分,说明如果 $x$ 属于并集,那么一定存在一个能让新验证器接受的证书。

5. $V_{1}(x, c) \text { accepts } \Rightarrow x \in L_{1}$

- 解释: 这是验证器 $V_1$ 的可靠性,如果 $V_1$ 接受了,那么输入 $x$ 一定属于语言 $L_1$。

6. $V_{2}(x, c) \text { accepts } \Rightarrow x \in L_{2}$

- 解释: 这是验证器 $V_2$ 的可靠性,与上一条类似。

98. 全文总结与核心要点

📖 [逐步解释]

本部分旨在对整个“讲义 11B:复杂性复习 - 解答”进行一次高层次的总结,提炼出每个练习所揭示的核心概念与思想。通过这次回顾,我们可以将孤立的知识点串联起来,形成对计算复杂性理论更宏观和深刻的理解。

📝 [总结]

这份讲义通过五个循序渐进的练习,深刻地探讨了计算复杂性理论的几个基石性概念:

  1. 增长率的区分: 讲解了多项式时间(P类问题的标志)与指数时间的本质区别,这是划分“易解”与“难解”问题的第一道门槛。
  2. 复杂性类的性质: 通过证明NP运算封闭,展示了如何通过形式化方法研究复杂性类自身的结构特性。
  3. 参数的决定性作用: 通过对比k-CliqueClique,鲜明地揭示了问题定义中一个参数是“常数”还是“变量”,可以如何戏剧性地改变问题的复杂性,是理解参数化复杂性的绝佳入口。
  4. 重大猜想的深远影响: 通过探索P=NP的推论,展示了这个理论猜想若被证实,将如何颠覆我们对整个计算世界的认知,使几乎所有非平凡的“简单”问题都变得“最难”。
  5. 问题的非对称性: 通过SPATHLPATH的对比,揭示了在问题描述上看似微小的改动(“至多”vs“至少”),可能导致其内在复杂性发生从PNP-完全的质变,强调了算法设计的微妙性和问题内在结构的决定性。
🎯 [存在目的]

本最终总结部分的存在,是为了帮助读者从具体的证明细节中跳脱出来,鸟瞰整个知识图景。它将各个练习的核心“寓意”联系在一起,巩固了对复杂性理论核心思想的直觉和理解,确保学习者不仅掌握了“如何证明”,更理解了“为何要这样证明”以及这些证明“揭示了什么”。

🧠 [直觉心智模型]

可以将整个讲义看作一次“计算世界”的探索之旅:

  1. 练习1是学习识别地图上的两种基本地形:“平原”(多项式)和“陡峭山脉”(指数)。
  2. 练习2是发现“平原”区域的一些地理规则,比如两个“NP平原”合并后还是一片“NP平原”。
  3. 练习3是学习看等高线,理解一个地方的地势是固定的(k常数),还是会根据你走的位置变化而变化(k是变量)。
  4. 练习4是一个思想实验,想象如果所有“山脉”都被夷为平地(P=NP),世界会变成什么样——一个所有地方都同样“难走”的奇异景象。
  5. 练习5是发现两条看似平行的路径,一条是轻松的下坡路(SPATH),另一条却是通往未知险峰的攀岩路线(LPATH),告诉我们方向和目标的重要性。

这次总结,就是站在旅途的终点,回顾一路上的风景,将它们串联成一幅完整的“计算复杂性世界地图”。

💭 [直观想象]

想象你刚刚看完一部由五个短片组成的电影。每个短片都讲述了一个关于“难度”的故事。本部总结就像是电影结束后的导演访谈或影评分析,它将五个独立的故事联系起来,揭示了它们共同的主题:“计算的极限是什么?”以及“我们如何精确地描述和度量这种极限?”。它帮助你将零散的观影感受整合成对导演(在此即为复杂性理论)核心思想的深刻洞见。

[[END_OF_RESPONSE]]所有解释内容已全部输出完毕。