还没有笔记
选中页面文字后点击「高亮」按钮添加
📜 [原文1]
即使一个问题原则上是可判定的,因此在计算上是可解决的,但如果其解决方案需要过多的时间或内存,那么在实践中可能无法解决。在本书的最后一部分,我们介绍了计算复杂度理论——对解决计算问题所需的时间、内存或其他资源的研究。我们从时间开始。
本章的目的是介绍时间复杂度理论的基础知识。首先,我们介绍一种衡量解决问题所需时间的方法。然后,我们展示如何根据所需时间量对问题进行分类。之后,我们讨论某些可判定问题可能需要大量时间的可能性,以及如何确定何时面临此类问题。
这部分内容是计算理论中一个全新篇章的开篇介绍,它在 可计算性理论 的基础上引入了一个新的、更贴近现实的维度:效率。
在前面的章节中,我们主要关心的是“一个问题能不能被解决?”(即可判定性问题)。我们通过图灵机等计算模型,将问题划分为可判定的(存在一个图灵机能在有限时间内给出“是”或“否”的答案)和不可判定的(不存在这样的图灵机)。
然而,仅仅知道一个问题“能被解决”在现实世界中是远远不够的。这里的核心思想是:“能解决”不等于“能实际解决”。一个理论上存在的解决方案,如果需要的时间比宇宙的年龄还长,或者需要的存储空间超过地球上所有硬盘的总和,那么这个解决方案对于我们来说就是没有实际意义的。
计算复杂度理论 (Computational Complexity Theory) 正是研究这个问题的学科。它不再仅仅问“能不能”,而是问“需要多少资源才能解决?”。这里的“资源”是计算过程中消耗的各种成本,最核心、最常见的两个是:
本段明确指出,本书的最后部分将聚焦于计算复杂度理论,并且首先从“时间”这个资源开始切入。
接下来,本章的学习路径被清晰地规划出来:
假设一个推销员需要访问100个城市,每个城市只去一次,最后回到起点,他想找到最短的总路程。这是一个经典的可判定问题,我们称之为旅行商问题 (TSP)。最直接的解法是“暴力枚举”:列出所有可能的访问顺序(排列组合),计算每种顺序的总路程,然后找出最小的那个。
假设需要对100万个学生的成绩进行排序。这是一个可判定的问题。
计算复杂度理论不仅区分“可行”与“不可行”,还在“可行”的范围内,进一步区分“高效”与“低效”。
本段是计算复杂度理论的引言,核心思想是:在可计算性(一个问题能否被解决)之上,增加了一个效率的维度(解决该问题需要多少资源)。本章将聚焦于时间资源,旨在建立一套衡量和分类计算问题时间需求的方法论,并学会识别那些理论上可解但实践上因耗时过长而难以解决的“困难”问题。
本段的目的是完成从“可计算性理论”到“计算复杂度理论”的过渡。它为读者建立了新的思维框架:从只关心“存在性”(是否存在算法)转向关心“性能”(算法的资源消耗)。这为后续引入大O记法、时间复杂度类(如P和NP)等核心概念奠定了基础,是连接理论与实践的关键桥梁。
想象一下你想挖一条从地球一端到另一端的隧道。
📜 [原文2]
我们从一个例子开始。考虑语言 $A=\left\{0^{k} 1^{k} \mid k \geq 0\right\}$。显然,$A$ 是一种可判定语言。一个单带图灵机需要多少时间来判定 $A$?我们检查下面用于 $A$ 的单带 TM $M_{1}$。我们给出
图灵机的低级别描述,包括磁带上的实际磁头移动,以便我们可以计算 $M_{1}$ 运行时使用的步数。
$M_{1}=$“在输入字符串 $w$ 上:
我们将分析 TM $M_{1}$ 判定 $A$ 的算法,以确定它使用了多少时间。首先,我们为此目的引入一些术语和符号。
算法在特定输入上使用的步数可能取决于几个参数。例如,如果输入是图,步数可能取决于节点数、边数、图的最大度,或者这些因素和/或其他因素的某种组合。为简单起见,我们仅将算法的运行时间计算为表示输入字符串长度的函数,而不考虑任何其他参数。在最坏情况分析中,我们在此考虑的形式,我们考虑特定长度所有输入中最长的运行时间。在平均情况分析中,我们考虑特定长度所有输入运行时间的平均值。
这一部分开始具体实践上一节提出的目标:如何衡量一个算法的运行时间。它通过一个具体的例子——判定语言 $A=\left\{0^{k} 1^{k} \mid k \geq 0\right\}$——来引导我们思考。
本节通过分析一个用于判定语言 $A=\{0^k1^k\}$ 的具体图灵机算法 $M_1$,引出了衡量算法时间复杂度的基本方法。核心要点是:1) 必须基于一个具体的、低级别的算法模型来分析;2) 算法的运行时间被定义为计算步数关于输入长度 $n$ 的函数;3) 我们主要采用最坏情况分析,即关注在所有长度为 $n$ 的输入中,那个使算法运行最久的情况,以此作为性能的上界保证。
此部分的目的是将“衡量复杂度”这一抽象概念具体化、可操作化。它通过一个简单但非平凡的例子,手把手地展示了分析过程的思考路径:从问题到算法,再到定义分析框架(最坏情况、输入规模)。这为后面引入大O记法等形式化工具铺平了道路,让读者明白这些工具是为了解决什么问题而生的。
分析算法时间复杂度,就像是评估一位快递员完成一次派送任务所需的时间。
想象一下你的任务是用一支笔和一张长长的纸带(图灵机磁带)来验证一串写着 000111 的字符串是否符合“等量0和1”的规则。
你的算法 ($M_1$) 是这样的:
分析这个过程的时间,你会发现,最花时间的部分就是你每次都要“回到开头”再重新扫描。纸带越长(输入规模 $n$ 越大),你来回跑的次数和每次跑的路程就越长。这就是算法时间复杂度的直观体现。
📜 [原文3]
令 $M$ 是一个在所有输入上都停机的确定性图灵机。$M$ 的运行时间或时间复杂度是函数 $f: \mathcal{N} \longrightarrow \mathcal{N}$,其中 $f(n)$ 是 $M$ 在任何长度为 $n$ 的输入上使用的最大步数。如果 $f(n)$ 是 $M$ 的运行时间,我们说 $M$ 在 $f(n)$ 时间内运行,并且 $M$ 是一个 $f(n)$ 时间的图灵机。习惯上我们用 $n$ 来表示输入的长度。
这是对时间复杂度的第一个形式化定义,它精确地阐述了前文讨论的概念。让我们逐句拆解:
假设有一个图灵机 $M_{scan}$,它的功能是:对于任何输入字符串(字母表为{a, b}),它从左到右扫描一遍,然后接受。
假设有一个图灵机 $M_{double}$,它的功能是:对于输入 $0^k$,它在后面添加 $k$ 个 $0$,最后输出 $0^{2k}$。
定义7.1为“一个确定性图灵机的时间复杂度”提供了严格的数学描述。它将时间复杂度定义为一个函数 $f(n)$,其中 $n$ 是输入字符串的长度,$f(n)$ 的值是在所有长度为 $n$ 的输入中,该图灵机所需的最大计算步数。这个定义是最坏情况分析的体现,并且是后续所有时间复杂度讨论的基石。
本定义的目的是将之前非形式化的讨论“固化”为一个精确、无歧义的数学对象——函数 $f(n)$。有了这个定义,我们就可以脱离模糊的语言描述,转而使用数学工具(如函数比较、极限、不等式)来分析和比较算法的效率,为建立整个复杂度理论大厦提供了第一块基石。
将图灵机 $M$ 想象成一个工人,他的工作是处理写在纸带上的订单。
想象一个迷宫(代表图灵机的一次计算)。从起点(初始状态)到终点(接受或拒绝状态)有很多条路径。
📜 [原文4]
因为算法的精确运行时间通常是一个复杂的表达式,所以我们通常只对其进行估计。在一种方便的估计形式中,称为渐近分析,我们试图理解算法在大型输入上运行时所需的运行时间。我们通过只考虑算法运行时间表达式的最高阶项来实现这一点,忽略该项的系数和任何低阶项,因为最高阶项在大型输入上支配其他项。
例如,函数 $f(n)=6 n^{3}+2 n^{2}+20 n+45$ 有四项,最高阶项是 $6 n^{3}$。忽略系数 6,我们说 $f$ 渐近地至多为 $n^{3}$。描述这种关系的渐近记法或大O记法是 $f(n)=O\left(n^{3}\right)$。我们在以下定义中形式化这一概念。令 $\mathcal{R}^{+}$为非负实数集。
这部分引入了复杂度理论中最重要的数学工具之一:渐近分析 (Asymptotic Analysis) 和 大O记法 (Big-O Notation)。
我们来看看当 $n$ 变大时,各项的占比:
这个例子清晰地表明,随着 $n$ 的增大,低阶项 ($2n^2, 20n, 45$) 的影响变得微不足道,真正决定函数大小的是 $6n^3$。渐近分析正是基于这一事实。
本节阐述了在时间复杂度分析中引入渐近分析和大O记法的必要性。由于精确的运行时间表达式过于复杂且包含非本质信息,我们通过渐近分析来关注当输入规模 $n$ 足够大时,运行时间的增长趋势。具体做法是:保留最高阶项,并忽略其系数和所有低阶项。大O记法(如 $O(n^3)$)就是这种分析形式化的数学语言,它为函数的增长率提供了一个上界。
本节的目的是引入一种强大的抽象工具,将算法分析从对具体公式的繁琐计算中解放出来。大O记法提供了一种通用语言,使得不同算法的效率可以在一个统一的、忽略实现细节和硬件差异的框架下进行有意义的比较。它是整个计算复杂度理论的基石和通用语言。
大O记法就像是给一个人的财富评定“数量级”。
想象你在开一辆车,车的速度由一个复杂的公式决定:$v(t) = 6t^3 + 2t^2 + 20t + 45$ (t是时间)。
📜 [原文5]
令 $f$ 和 $g$ 是函数 $f, g: \mathcal{N} \longrightarrow \mathcal{R}^{+}$。我们说 $\boldsymbol{f}(\boldsymbol{n})=\boldsymbol{O}(\boldsymbol{g}(\boldsymbol{n}))$,如果存在正整数 $c$ 和 $n_{0}$,使得对于每个整数 $n \geq n_{0}$,
当 $f(n)=O(g(n))$ 时,我们说 $g(n)$ 是 $f(n)$ 的上界,或者更精确地说,$g(n)$ 是 $f(n)$ 的渐近上界,以强调我们忽略了常数因子。
这是大O记法的严格数学定义,它将前面直观的想法用精确的逻辑语言表达出来。让我们来解剖这个定义。
“令 $f$ 和 $g$ 是函数 $f, g: \mathcal{N} \longrightarrow \mathcal{R}^{+}$。”
“我们说 $f(n)=O(g(n))$,如果...”
“...存在正整数 $c$ 和 $n_{0}$...”
“...使得对于每个整数 $n \geq n_{0}$,”
“$f(n) \leq c g(n)$”
总结术语
我们需要找到一对正整数 $(c, n_0)$,使得对于所有 $n \geq n_0$,都有 $6n^3 + 2n^2 + 20n + 45 \leq c \cdot n^3$。
推导过程:
我们的目标是让右边的 $c \cdot n^3$ “压住”左边的每一项。
$6n^3 + 2n^2 + 20n + 45 \leq 6n^3 + 2n^3 + 20n^3 + 45n^3$ (当 $n \geq 1$ 时成立,因为 $n^2 \leq n^3$, $n \leq n^3$, $1 \leq n^3$)
$ \leq (6+2+20+45) n^3$
$ = 73 n^3$
所以,我们发现,只要 $n \geq 1$,就有 $f(n) \leq 73n^3$。
因此,我们可以选择 $c=73, n_0=1$。
既然我们成功地找到了一对 $(c, n_0)$,根据定义,我们证明了 $f(n) = O(n^3)$。
另一种选择:
我们也可以选择不同的 $c$。比如,我们想让 $c$ 小一点。
$6n^3 + 2n^2 + 20n + 45 \leq c n^3$
两边除以 $n^3$ (假设 $n>0$):
$6 + \frac{2}{n} + \frac{20}{n^2} + \frac{45}{n^3} \leq c$
当 $n$ 增大时,$\frac{2}{n}, \frac{20}{n^2}, \frac{45}{n^3}$ 这些项都在变小。
当 $n=1$ 时,左边是 $6+2+20+45 = 73$。
当 $n=10$ 时,左边是 $6 + 0.2 + 0.2 + 0.045 = 6.445$。
如果我们选择 $c=7$,那么我们需要解不等式 $6 + \frac{2}{n} + \frac{20}{n^2} + \frac{45}{n^3} \leq 7$。
$\frac{2}{n} + \frac{20}{n^2} + \frac{45}{n^3} \leq 1$。
这个不等式对于比如 $n_0=10$ 肯定是成立的 ($0.2+0.2+0.045 = 0.445 \leq 1$)。
所以,我们也可以选择 $c=7, n_0=10$。这也证明了 $f(n) = O(n^3)$。
这说明了 $(c, n_0)$ 的选择不是唯一的。
我们需要找到 $(c, n_0)$ 使得 $100n \leq c n^2$ 对所有 $n \geq n_0$ 成立。
两边除以 $n$ (假设 $n>0$): $100 \leq cn$。
如果我们选择 $c=1$,那么需要 $100 \leq n$。所以我们可以取 $n_0 = 100$。
因此,选择 $c=1, n_0=100$ 可以证明 $100n = O(n^2)$。
这个例子说明,大O给出的上界可以是很宽松的。$n^2$ 的增长速度远快于 $100n$,所以它当然是一个有效的上界。
定义7.2用严格的数学语言 formalize 了大O记法。它指出,$f(n)=O(g(n))$ 成立,意味着我们可以找到一个常数 $c$ 和一个起始点 $n_0$,从 $n_0$ 开始,函数 $f(n)$ 的值永远不会超过 $g(n)$ 的 $c$ 倍。这为 $f(n)$ 的增长提供了一个渐近上界。
这个定义的目的是提供一个坚实的、无歧义的逻辑基础,以便在此之上进行所有关于算法效率的数学推导和证明。它将直观的“抓大放小”思想,转化为一个可以被严格验证或否证的数学命题,是算法分析的基石。
把 $f(n)$ 和 $g(n)$ 想象成两棵树的生长高度。
想象 $f(n)$ 是你每天的开销,它可能因为各种原因波动,比如 $f(n) = 6n^3 + ...$ (这里的 $n$ 是第 $n$ 天)。$g(n)=n^3$ 是一个简化的开销模型。
你说你的开销是 $O(n^3)$,意思是:
“我知道我每天花钱的精确数目很复杂,但你听我说个大概。我可能一开始(头几天, $n < n_0$)花钱没个准,甚至有几天花销特别大。但是,我向你保证,存在一个‘挥霍系数’ $c$(比如 $c=73$)和一个起始日期 $n_0$(比如从第1天开始),从那天起,我每天的开销 $f(n)$ 绝对不会超过 $73 \times n^3$ 这个数额。我的消费水平,从长远来看,被 $n^3$ 这个模型给框住了。”
📜 [原文6]
令 $f_{1}(n)$ 是函数 $5 n^{3}+2 n^{2}+22 n+6$。那么,选择最高阶项 $5 n^{3}$ 并忽略其系数 5 得到 $f_{1}(n)=O\left(n^{3}\right)$。
我们来验证这个结果是否满足形式定义。我们通过令 $c$ 为 6 且 $n_{0}$ 为 10 来实现。那么,对于每个 $n \geq 10$,有 $5 n^{3}+2 n^{2}+22 n+6 \leq 6 n^{3}$。
此外,$f_{1}(n)=O\left(n^{4}\right)$,因为 $n^{4}$ 大于 $n^{3}$,因此仍然是 $f_{1}$ 的渐近上界。
然而,$f_{1}(n)$ 不是 $O\left(n^{2}\right)$。无论我们给 $c$ 和 $n_{0}$ 赋什么值,在这种情况下定义仍然不满足。
这个示例通过一个具体的函数 $f_1(n)$,演示了如何应用大O记法的定义,并阐明了关于上界的一些重要性质。
示例7.3通过一个实例强化了对大O记法的理解:
本示例的目的是将抽象的定义7.2与实际操作联系起来,让读者亲手“玩”一遍大O记法的证明与证伪过程。通过正例($O(n^3), O(n^4)$)和反例($O(n^2)$),加深读者对“上界”、“渐近”和“常数因子”等核心概念的理解。
大O记法就像给快速增长的物体找一个“生长通道”。
想象 $f_1(n)$ 是一枚发射的火箭,它的飞行高度函数非常复杂。
📜 [原文7]
大-$O$ 与对数以一种特殊的方式相互作用。通常当我们使用对数时,我们必须指定底数,如 $x=\log _{2} n$。这里的底数 2 表示这个等式等价于 $2^{x}=n$。改变底数 $b$ 的值会使 $\log _{b} n$ 的值改变一个常数因子,这归因于恒等式 $\log _{b} n=\log _{2} n / \log _{2} b$。因此,当我们写 $f(n)=O(\log n)$ 时,不再需要指定底数,因为我们反正都在忽略常数因子。
令 $f_{2}(n)$ 是函数 $3 n \log _{2} n+5 n \log _{2} \log _{2} n+2$。在这种情况下,我们有 $f_{2}(n)=O(n \log n)$,因为 $\log n$ 支配 $\log \log n$。
大-$O$ 记法也出现在算术表达式中,例如表达式 $f(n)=O\left(n^{2}\right)+O(n)$。在这种情况下,每个 $O$ 符号的出现代表一个不同的被抑制的常数。由于 $O\left(n^{2}\right)$ 项支配 $O(n)$ 项,所以该表达式等价于 $f(n)=O\left(n^{2}\right)$。当 $O$ 符号出现在指数中时,如表达式 $f(n)=2^{O(n)}$,同样的思想适用。该表达式表示对于某个常数 $c$,存在一个 $2^{c n}$ 的上界。
表达式 $f(n)=2^{O(\log n)}$ 出出现在某些分析中。使用恒等式 $n=2^{\log _{2} n}$,因此 $n^{c}=2^{c \log _{2} n}$,我们看到 $2^{O(\log n)}$ 表示对于某个 $c$,存在一个 $n^{c}$ 的上界。表达式 $n^{O(1)}$ 以另一种方式表示相同的界,因为表达式 $O(1)$ 表示一个值,它从不超过一个固定的常数。
这个示例集中展示了大O记法在处理对数 (logarithm)、表达式加法和指数时的一些常用规则和技巧。
示例7.4讲解了大O记法的几个重要应用和性质:
本示例的目的是扩展读者使用大O记法的技能,使其能够处理更复杂的表达式,特别是那些涉及对数和指数的。这些都是在实际算法分析中频繁出现的模式。理解这些规则,尤其是多项式界和指数界的区别,对于后续学习P vs NP等核心理论至关重要。
大O的算术规则就像是比较不同“物种”的“战斗力”:
想象不同函数的增长曲线是一条条不同的赛道。
大O记法就是帮你判断,一个复杂的、由多段组成的赛道,其最终的爬坡难度是由哪一段最陡峭的赛道决定的。
📜 [原文8]
大-$O$ 记法有一个伴随称为小o记法。大-$O$ 记法表示一个函数渐近地不超过另一个函数。要表示一个函数渐近地小于另一个函数,我们使用小o记法。大-$O$ 和小o记法之间的区别类似于 $\leq$ 和 $<$ 之间的区别。
令 $f$ 和 $g$ 是函数 $f, g: \mathcal{N} \longrightarrow \mathcal{R}^{+}$。如果
我们说 $\boldsymbol{f}(\boldsymbol{n})=\boldsymbol{o}(\boldsymbol{g}(\boldsymbol{n}))$。
换句话说,$f(n)=o(g(n))$ 意味着对于任何实数 $c>0$,存在一个数 $n_{0}$,使得对于所有 $n \geq n_{0}$,有 $f(n)<c g(n)$。
这部分介绍了大O记法的“近亲”——小o记法 (Little-o Notation)。
$f(n) = n$, $g(n) = n^2$。
$\lim_{n \to \infty} \frac{f(n)}{g(n)} = \lim_{n \to \infty} \frac{n}{n^2} = \lim_{n \to \infty} \frac{1}{n}$。
当 $n$ 趋于无穷大时,$\frac{1}{n}$ 趋于 0。
因为极限为0,所以 $n = o(n^2)$。
$f(n) = n^2$, $g(n) = n^2$。
$\lim_{n \to \infty} \frac{f(n)}{g(n)} = \lim_{n \to \infty} \frac{n^2}{n^2} = \lim_{n \to \infty} 1 = 1$。
极限是1,不是0。所以 $n^2$ 不是 $o(n^2)$。(实际上,$n^2=O(n^2)$ 且 $n^2=\Omega(n^2)$,所以 $n^2 = \Theta(n^2)$)。
定义7.5引入了小o记法,它表示一个函数在渐近意义上严格小于另一个函数。这与大O记法的“小于或等于”形成了对比。$f(n)=o(g(n))$ 可以通过证明 $\lim_{n \to \infty} f(n)/g(n) = 0$ 来确定,它意味着 $f(n)$ 的增长被 $g(n)$ 完全支配。
引入小o记法是为了提供一种更精细的分析工具。当我们需要强调一个上界不是“紧”的时候,或者需要表达一个算法的复杂度严格优于某个界限时,小o记法是比大O记法更精确、更有力的表述。例如,在证明某些问题的复杂度下界时,它非常有用。
回到财富评级的比喻:
想象两名赛跑者,$f(n)$ 和 $g(n)$,他们的速度在第 $n$ 秒分别是 $f(n)$ 和 $g(n)$。
📜 [原文9]
以下内容很容易验证。
然而,$f(n)$ 从来不是 $o(f(n))$。$\square$
这个示例列举了一系列常见的函数增长速度的比较,都使用了小o记法来表示严格的渐近小于关系。这构成了我们常说的“复杂度阶梯”的一部分。我们将逐一验证它们。验证的主要工具是极限法则:$\lim_{n \to \infty} \frac{f(n)}{g(n)} = 0$。
最后一句:“然而,$f(n)$ 从来不是 $o(f(n))$。”
让我们用数值来感受一下这些函数的增长差异,假设 $n = 2^{20} \approx 10^6$ (一百万)。
这些数值清晰地展示了“严格慢于”的含义。
示例7.6通过一系列对比,建立了一个常见时间复杂度函数的增长速度排序:
常数 < $\log \log n$ < $\log n$ < $\sqrt{n}$ < $n$ < $n \log \log n$ < $n \log n$ < $n^2$ < $n^3$ < ... < $2^n$ < $n!$ < $n^n$
这个“复杂度阶梯”是算法分析的核心参考。示例还明确了任何函数 $f(n)$ 都不可能是 $o(f(n))$,这与“严格小于”的直觉相符。
本示例的目的是让读者熟悉并内化这些常见函数的相对增长率。在未来分析算法时,能够快速判断一个复杂表达式中哪个是主导项,哪个可以被忽略,是至关重要的技能。这个示例为培养这种“复杂度直觉”提供了基础训练。
将不同的复杂度函数想象成不同的交通工具:
小o记法就是确认,比如,自行车的速度严格慢于汽车,汽车严格慢于高铁。
想象一个排行榜,上面是各种函数的“权力值”。
$f(n) = o(g(n))$ 意味着 $g(n)$ 的权力等级严格高于 $f(n)$。
这个排行榜等级森严,低等级永远无法超越高等级。一个函数自己和自己的权力等级是相等的,所以 $f(n)$ 不可能严格小于 $f(n)$。
📜 [原文10]
我们来分析为语言 $A=\left\{0^{k} 1^{k} \mid k \geq 0\right\}$ 给出的 TM 算法。为方便起见,我们在此重复该算法。
$M_{1}=$“在输入字符串 $w$ 上:
为了分析 $M_{1}$,我们分别考虑其四个阶段。在阶段 1 中,机器扫描磁带以验证输入是否为 $0^{*} 1^{*}$ 的形式。执行此扫描需要 $n$ 步。如前所述,我们通常用 $n$ 来表示输入的长度。将磁头重新定位到磁带左端需要另外 $n$ 步。因此,此阶段总共使用了 $2n$ 步。在大-$O$ 记法中,我们说此阶段使用了 $O(n)$ 步。请注意,我们没有在机器描述中提及磁头重新定位。使用渐近记法允许我们省略机器描述中最多影响运行时间一个常数因子的细节。
在阶段 2 和 3 中,机器反复扫描磁带,并在每次扫描中划掉一个 0 和一个 1。每次扫描使用 $O(n)$ 步。因为每次扫描划掉两个符号,所以最多可以发生 $n/2$ 次扫描。因此,阶段 2 和 3 所花费的总时间是 $(n/2)O(n) = O(n^2)$ 步。
在阶段 4 中,机器进行一次扫描以决定接受或拒绝。此阶段花费的时间最多为 $O(n)$。
因此,$M_{1}$ 在长度为 $n$ 的输入上的总时间是 $O(n)+O\left(n^{2}\right)+O(n)$,即 $O\left(n^{2}\right)$。换句话说,它的运行时间是 $O\left(n^{2}\right)$,这完成了对该机器的时间分析。
这部分是全书第一个完整的时间复杂度分析实例,它将前面介绍的所有概念(图灵机步数、最坏情况、大O记法)串联起来,应用于算法 $M_1$。
分析阶段1:格式检查
分析阶段2和3:核心循环
分析阶段4:最终检查
汇总总时间复杂度
本节通过对图灵机 $M_1$ 的分阶段分析,完整地演示了如何计算一个算法的时间复杂度。分析过程遵循“分而治之”的策略,分别计算每个部分的复杂度,然后使用大O的加法和乘法规则将它们组合起来,最终由增长最快的“瓶颈”部分(本例中的嵌套循环)决定总体复杂度。$M_1$ 的时间复杂度被确定为 $O(n^2)$。
此部分的目的是将理论付诸实践,提供一个算法分析的“范本”。它让读者看到,一个看似简单的“来回划掉”的策略,在严格的单带图灵机模型下,会导致一个平方级别的时间复杂度。这为后续讨论更高效的算法以及不同计算模型(如多带图灵机)如何影响复杂度埋下了伏笔。
分析算法 $M_1$ 就像是分析一个工厂的生产流程。
想象你在一个很长的图书馆书架(磁带)前,书架上有 $n$ 本书,一半是红皮(0),一半是蓝皮(1),混在一起。你的任务是检查红皮书和蓝皮书的数量是否相等。
你的策略 ($M_1$)是:
不对,这个模拟不对,$M_1$的描述是“扫描磁带,划掉一个0和一个1”,这意味着一次扫描中完成两件事。
更准确的想像是:
你总共需要进行 $n/2$ 轮这样的标记。每一轮,你都可能需要把整个长长的书架走一遍。你走的总路程大约就是 (轮数) $\times$ (书架长度) = $(n/2) \times n$,这就是 $O(n^2)$ 的来源。
📜 [原文11]
令 $t: \mathcal{N} \longrightarrow \mathcal{R}^{+}$是一个函数。定义时间复杂度类 TIME($\boldsymbol{t}(\boldsymbol{n})$) 为所有可由 $O(t(n))$ 时间图灵机判定的语言的集合。
回想语言 $A=\left\{0^{k} 1^{k} \mid k \geq 0\right\}$。前面的分析表明 $A \in \operatorname{TIME}\left(n^{2}\right)$,因为 $M_{1}$ 在 $O\left(n^{2}\right)$ 时间内判定 $A$,并且 $\operatorname{TIME}\left(n^{2}\right)$ 包含所有可以在 $O\left(n^{2}\right)$ 时间内判定的语言。
这个定义引入了一个核心概念:时间复杂度类 (Time Complexity Class)。
定义7.7从对单个算法的分析,上升到了对一类问题的分类。时间复杂度类 TIME(t(n)) 是一个集合,它包含了所有能够被某个 $O(t(n))$ 时间的图灵机判定的语言。通过证明 $M_1$ 能在 $O(n^2)$ 时间内判定语言 $A$,我们得出结论 $A \in \operatorname{TIME}(n^2)$,即 $A$ 是一个可以在平方时间内解决的问题。
本定义的目的是建立一个框架,用于对计算问题的“难度”进行分类和比较。它使我们能够提出更有意义的问题,例如:“是否存在任何问题在 TIME(n^3) 中但不在 TIME(n^2) 中?” 这类问题是复杂度理论的核心,旨在探索计算的内在极限和不同难度等级之间的确切关系。这是从“工程”(分析特定算法)到“科学”(研究普适规律)的转变。
时间复杂度类就像是“武林高手段位认证”。
想象一个城市里有各种“快递服务等级”。
📜 [原文12]
是否存在一台机器可以渐近地更快地判定 $A$?换句话说,$A$ 是否在 $t(n)=o\left(n^{2}\right)$ 的 $\operatorname{TIME}(t(n))$ 中?我们可以通过在每次扫描中划掉两个 0 和两个 1 来改进运行时间,而不是只划掉一个,因为这样做可以将扫描次数减少一半。但这只会将运行时间改进 2 倍,并且不影响渐近运行时间。以下机器 $M_{2}$ 使用不同的方法来渐近地更快地判定 $A$。它表明 $A \in \operatorname{TIME}(n \log n)$。
$M_{2}=$“在输入字符串 $w$ 上:
这部分提出了一个关键问题:“我们还能做得更好吗?” 并给出了一个肯定的答案,引入了一个更巧妙、渐近更快的算法 $M_2$。
本节通过引入一个更巧妙的算法 $M_2$,挑战了 $M_1$ 的 $O(n^2)$ 复杂度。$M_2$ 的核心思想是在每次迭代中将 0 和 1 的数量减半,而不是减一。这使得循环次数从 $O(n)$ 级别锐减到 $O(\log n)$ 级别。虽然单次迭代的成本仍然是 $O(n)$,但总体的时间复杂度有望得到显著改善,从 $O(n^2)$ 降低。这表明语言 $A$ 确实属于一个比 $\operatorname{TIME}(n^2)$ 更快的复杂度类。
此部分的目的是为了说明:
寻找一个叛徒的游戏:
你有一大袋子红豆和一大袋子绿豆,你要确认它们的数量是否相等。
📜 [原文13]
在分析 $M_{2}$ 之前,我们先验证它确实判定 $A$。在阶段 4 中执行的每次扫描中,剩余 0 的总数减半,任何余数都被丢弃。因此,如果我们从 13 个 0 开始,在阶段 4 执行一次后,只剩下 6 个 0。在随后的执行中,剩下 3 个,然后 1 个,然后 0 个。此阶段对 1 的数量具有相同的影响。
现在我们检查阶段 3 每次执行时 0 的数量和 1 的数量的偶/奇奇偶性。再次考虑从 13 个 0 和 13 个 1 开始。阶段 3 的第一次执行发现奇数个 0(因为 13 是奇数)和奇数个 1。在随后的执行中,出现偶数个(6),然后奇数个(3),然后奇数个(1)。我们不会对 0 个 0 或 0 个 1 执行此阶段,因为阶段 2 中指定的重复循环条件。对于发现的奇偶性序列(奇数、偶数、奇数、奇数),如果我们将偶数替换为 0,奇数替换为 1,然后反转序列,我们得到 1101,即 13 的二进制表示,或者说是开始时 0 和 1 的数量。奇偶性序列总是给出二进制表示的反转。
当阶段 3 检查以确定剩余的 0 和 1 的总数是偶数时,它实际上是在检查 0 的奇偶性与 1 的奇偶性是否一致。如果所有奇偶性都一致,则 0 的数量和 1 的数量的二进制表示一致,因此这两个数字相等。
这段内容在分析 $M_2$ 的时间复杂度之前,先做了一件更重要的事情:证明算法的正确性。一个再快的算法,如果结果是错的,那就毫无意义。
本节详细阐述了算法 $M_2$ 的正确性原理。它通过在每次迭代中将数量减半(相当于二进制右移),并检查奇偶性(相当于读取二进制最低位),巧妙地实现了对初始0的数量和1的数量的二进制表示的逐位比较。只有当两个数字的二进制表示完全相同时,算法才会最终接受,从而保证了其正确性。
在展示一个更优的算法后,必须严格证明其正确性,这是算法设计和分析的基本步骤。本节的目的就是完成这一证明,让读者信服 $M_2$ 不仅快,而且对。同时,它也展示了一种非常规、但极为巧妙的算法设计思想,即从数字的二进制表示入手来解决计数问题。
比较两堆数量庞大的豆子是否相等 ($M_2$ 算法):
你不是一颗颗地数,而是和助手配合玩一个游戏。
如果每一次你们的回答都一样,直到最后豆子同时被拿完,那你们就可以断定,最初两堆豆子的数量是相等的。这个游戏过程,就是在逐位比较豆子数量的二进制表示。
想象有两个很长的二进制数字写在黑板上,你要判断它们是否相等。
$k_0 = 1101$
$k_1 = 1101$
你的比较方法 ($M_2$) 是:
$k_0 \to 110$
$k_1 \to 110$
$k_0 \to 11$
$k_1 \to 11$
$k_0 \to 1$
$k_1 \to 1$
$k_0 \to$ (空)
$k_1 \to$ (空)
数字都被擦完了,且每一步都匹配。所以原数相等。算法 $M_2$ 用物理操作(划掉磁带上的符号)模拟了这个“擦除并比较最低位”的过程。
📜 [原文14]
为了分析 $M_{2}$ 的运行时间,我们首先观察到每个阶段都需要 $O(n)$ 时间。然后我们确定每个阶段执行的次数。阶段 1 和 5 各执行一次,总共花费 $O(n)$ 时间。阶段 4 每次执行时至少划掉一半的 0 和 1,因此在所有都划掉之前,重复循环最多执行 $1+\log _{2} n$ 次迭代。因此,阶段 2、3 和 4 的总时间是 $(1+\log _{2} n) O(n)$,即 $O(n \log n)$。$M_{2}$ 的运行时间是 $O(n)+O(n \log n)=O(n \log n)$。
在证明了算法 $M_2$ 的正确性之后,现在我们来分析它的时间复杂度。
分析单次循环的成本
分析循环执行的次数
汇总总时间复杂度
本节完成了对算法 $M_2$ 的时间复杂度分析。通过确定其单次迭代成本为 $O(n)$(线性扫描),以及迭代次数为 $O(\log n)$(减半策略),得出其总时间复杂度为两者的乘积,即 $O(n \log n)$。这证明了 $M_2$ 确实是一个比 $M_1$ ($O(n^2)$) 渐近更快的算法。
此部分的目的是完成对 $M_2$ 的完整分析闭环(正确性+复杂度),并实际展示出不同算法设计思想(线性递减 vs 对数递减)所带来的渐近性能差异。它为“一个问题可以有不同复杂度的算法”这一观点提供了强有力的实例支撑,并确立了语言 $A$ 的一个更紧的时间复杂度上界:$A \in \operatorname{TIME}(n \log n)$。
对 $M_2$ 算法的分析,好比分析一种高效的会议决策流程。
想象在电话簿(一本按字母排序的人名列表,长度为 $n$)里查找一个特定名字“John Smith”。
📜 [原文15]
早些时候我们表明 $A \in \operatorname{TIME}\left(n^{2}\right)$,但现在我们有一个更好的界——即 $A \in \operatorname{TIME}(n \log n)$。这个结果在单带图灵机上无法进一步改进。事实上,任何可以在单带图灵机上在 $o(n \log n)$ 时间内判定的语言都是正则语言,如问题 7.20 要求您展示的那样。
如果图灵机有第二个磁带,我们可以在 $O(n)$ 时间(也称为线性时间)内判定语言 $A$。以下两带 TM $M_{3}$ 在线性时间内判定 $A$。机器 $M_{3}$ 的操作方式与之前用于 $A$ 的机器不同。它只是将 0 复制到其第二个磁带,然后将它们与 1 进行匹配。
$M_{3}=$“在输入字符串 $w$ 上:
这部分内容引出了计算模型对时间复杂度的深远影响,并展示了通过增强模型(从单带图灵机到多带图灵机)可以获得显著的性能提升。
本节通过为语言 $A$ 设计一个两带图灵机算法 $M_3$,证明了 $A \in \operatorname{TIME}(n)$。这与单带图灵机的最优解 $O(n \log n)$ 形成了鲜明对比。$M_3$ 的高效源于它利用第二条磁带作为独立的计数器,从而避免了单带模型中耗时的磁头来回移动。这个例子有力地说明了,计算模型的选择会直接影响一个问题的时间复杂度。
本节的核心目的是揭示计算复杂度与计算模型之间的紧密联系,这是复杂度理论区别于可计算性理论的一个关键特征。在可计算性理论中,丘奇-图灵论题告诉我们所有“合理”的计算模型在能力上是等价的。但本节表明,在复杂度理论中,这些模型在效率上不等价。这为后续讨论“什么是合理的复杂度衡量标准”以及不同模型之间的复杂度转换关系(如定理7.8)埋下了伏笔。
比较单带和两带图灵机,就像比较一个只有一只手的工人和一个有两只手的工人。
你正在核对一份长长的购物清单和你的购物车里的商品。
📜 [原文16]
这台机器很容易分析。四个阶段中的每个阶段都使用 $O(n)$ 步,因此总运行时间是 $O(n)$,因此是线性的。请注意,这个运行时间是最好的,因为仅仅读取输入就需要 $n$ 步。
让我们总结一下我们关于 $A$ 的时间复杂度,即判定 $A$ 所需的时间量所展示的内容。我们生产了一台单带 TM $M_{1}$,它在 $O\left(n^{2}\right)$ 时间内判定 $A$,以及一台更快的单带 TM $M_{2}$,它在 $O(n \log n)$ 时间内判定 $A$。问题 7.20 的解决方案意味着没有单带 TM 可以更快地完成。然后我们展示了一台两带 TM $M_{3}$,它在 $O(n)$ 时间内判定 $A$。因此,在单带 TM 上 $A$ 的时间复杂度是 $O(n \log n)$,在两带 TM 上是 $O(n)$。请注意,$A$ 的复杂度取决于所选择的计算模型。
这一讨论强调了复杂度理论与可计算性理论之间的重要区别。在可计算性理论中,丘奇-图灵论题意味着所有合理的计算模型都是等价的——也就是说,它们都判定相同类别的语言。在复杂度理论中,模型的选择会影响语言的时间复杂度。例如,在一个模型上可在线性时间内判定的语言,在另一个模型上不一定能在线性时间内判定。
在复杂度理论中,我们根据计算问题的时间复杂度对其进行分类。但是我们用哪种模型来衡量时间呢?相同的语言在不同的模型上可能有不同的时间要求。
幸运的是,对于典型的确定性模型,时间要求差异不大。因此,如果我们的分类系统对复杂度相对较小的差异不那么敏感,那么确定性模型的选择并不关键。我们将在接下来的几节中进一步讨论这个想法。
这部分内容对前面关于语言 $A$ 的所有分析进行了总结,并升华到一个核心的理论高度:计算模型的选择对时间复杂度至关重要。
本节总结了对语言 $A$ 的复杂度探索,得出了在单带和两带图灵机上其最优时间复杂度分别为 $O(n \log n)$ 和 $O(n)$ 的结论。这一差异凸显了计算模型在复杂度理论中的核心地位,与模型在可计算性理论中的可替换性形成对比。最后,文章展望了解决模型依赖问题的思路:建立对多项式级别差异不敏感的、更宏观的复杂度分类体系。
此部分的目的是完成从具体实例分析到抽象理论思考的升华。它利用语言 $A$ 的案例,提出了复杂度理论中的一个根本性问题——“以谁为准?”,并给出了一个方向性的解答。这为后续引入和定义像 P、NP 这样独立于具体模型的、更加稳健和普适的复杂度类奠定了哲学基础和必要性。
讨论计算模型和复杂度,就像讨论交通工具和到达时间。
你在不同的厨房里做同一道菜(判定语言A)。
📜 [原文17]
令 $t(n)$ 是一个函数,其中 $t(n) \geq n$。那么,每个 $t(n)$ 时间的多带图灵机都有一台等价的 $O\left(t^{2}(n)\right)$ 时间的单带图灵机。
这个定理是复杂度理论中的一个基础性结果,它精确地量化了多带图灵机和单带图灵机这两个计算模型之间的时间效率差异。
定理本身是一个陈述,其核心是复杂度关系:
$T_{multi-tape}(n) = t(n) \implies T_{single-tape}(n) = O(t(n)^2)$
定理7.8建立了一个重要的复杂度关系:任何一个能在多带图灵机上以 $t(n)$ 时间解决的问题,都可以在单带图リング机上以 $O(t^2(n))$ 时间解决。这个定理通过提供一个通用的模拟方法,量化了从“高级”模型到“基础”模型的时间成本,证明了这种转换最多导致多项式级别的性能下降。
本定理的目的是为了支撑“复杂度类的模型无关性”(在多项式级别上)这一核心思想。它通过严格的数学证明,为后续将“多项式时间”定义为一个不依赖于具体确定性模型的、稳健的复杂度类(P类)铺平了道路。这是复杂度理论为了摆脱模型依赖、寻求普适规律而迈出的关键一步。
这定理就像是在翻译一本用“高级语言”(多带TM)写的书到“基础语言”(单带TM)。
想象一个顶级大厨(多带TM)在做一个复杂的蛋糕,他有好多只手,可以同时打蛋、和面、调节烤箱。他做完需要 $t(n)$ 分钟。
现在你想让一个只有两只手的普通厨师(单带TM)完全模仿他的动作来做出同样的蛋糕。
📜 [原文18]
证明思路 该定理的证明思想非常简单。回想在定理 3.13 中,我们展示了如何将任何多带 TM 转换为模拟它的单带 TM。现在我们分析该模拟以确定它需要多少额外时间。我们证明模拟多带机器的每一步在单带机器上最多使用 $O(t(n))$ 步。因此,使用的总时间是 $O\left(t^{2}(n)\right)$ 步。
这部分概述了证明定理7.8的整体策略。它不是直接给出细节,而是提供了一个高层次的路线图,让读者先抓住核心逻辑。
证明思路部分将一个大问题分解为两个小问题:
该思路清晰地指出了证明的核心在于对“单步模拟”的成本分析,并预告了其结果为 $O(t(n))$,从而自然地导出最终结论 $O(t^2(n))$。
在给出冗长的形式化证明之前,提供一个“证明思路”或“proof sketch”是学术写作的常见做法。其目的在于:
这就像是在做一份项目计划,来估算一项庞大的“翻译”工程需要多久。
你是一个单核CPU(单带TM),要去模拟一个多核CPU(多带TM)的工作。多核CPU在一个时钟周期(一步)里,每个核都完成了一项任务。
📜 [原文19]
证明 令 $M$ 是一台在 $t(n)$ 时间内运行的 $k$ 带 TM。我们构造一台在 $O\left(t^{2}(n)\right)$ 时间内运行的单带 TM $S$。
机器 $S$ 通过模拟 $M$ 来操作,如定理 3.13 中所述。为了回顾该模拟,我们回想 $S$ 使用其单带表示 $M$ 的所有 $k$ 个磁带上的内容。磁带连续存储,其中 $M$ 的磁头位置标记在相应的方格上。
最初,$S$ 将其磁带格式化为表示 $M$ 所有磁带的格式,然后模拟 $M$ 的步骤。为了模拟一步,$S$ 扫描其磁带上存储的所有信息,以确定 $M$ 磁头下的符号。然后 $S$ 再次扫描其磁带,以更新磁带内容和磁头位置。如果 $M$ 的一个磁头向右移动到其磁带上以前未读取的部分,则 $S$ 必须增加分配给该磁带的空间量。它通过将其自身磁带的一部分向右移动一个单元格来实现。
现在我们分析这个模拟。对于 $M$ 的每一步,机器 $S$ 对其活动部分进行两次扫描。第一次获得确定下一步行动所需的信息,第二次执行该行动。$S$ 磁带活动部分的长度决定了 $S$ 扫描它所需的时间,所以我们必须确定这个长度的上限。为此,我们取 $M$ 的 $k$ 个磁带活动部分长度的总和。每个活动部分的长度最多为 $t(n)$,因为如果磁头每一步都向右移动,$M$ 在 $t(n)$ 步中使用了 $t(n)$ 个磁带单元格,如果磁头曾向左移动,则更少。因此,扫描 $S$ 磁带的活动部分使用 $O(t(n))$ 步。
为了模拟 $M$ 的每一步,$S$ 执行两次扫描,并且可能多达 $k$ 次向右移动。每次使用 $O(t(n))$ 时间,因此 $S$ 模拟 $M$ 的一步所需总时间是 $O(t(n))$。
现在我们限定模拟所用的总时间。初始阶段,$S$ 将其磁带格式化为正确的格式,使用 $O(n)$ 步。之后,$S$ 模拟 $M$ 的 $t(n)$ 步,每步使用 $O(t(n))$ 步,因此模拟的这一部分
使用 $t(n) \times O(t(n))=O\left(t^{2}(n)\right)$ 步。因此,$M$ 的整个模拟使用了 $O(n)+O\left(t^{2}(n)\right)$ 步。
我们假设 $t(n) \geq n$(一个合理的假设,因为 $M$ 甚至无法在更短的时间内读取整个输入)。因此,$S$ 的运行时间是 $O\left(t^{2}(n)\right)$,证明完成。
这是定理7.8的详细形式化证明,它将前面“证明思路”中的每一步都具体化。
1. 建立模拟环境
2. 分析模拟的各个阶段
阶段一:初始化 (Initial Setup)
阶段二:模拟 $M$ 的一步 (Single Step Simulation)
这是证明的核心,即对“证明思路”中“模拟一步的代价”的详细分析。为了模拟 $M$ 的一步, $S$ 需要:
3. 计算总模拟时间
4. 最终结论
详细证明通过严谨地分析单带图灵机 $S$ 模拟多带图灵机 $M$ 的过程,得出了最终的时间复杂度关系。证明的核心在于确定模拟 $M$ 的一步所需的时间。这个时间由三次操作主导:一次扫描以收集信息,一次扫描以更新状态,以及可能的磁带移位操作。由于 $M$ 的总活动空间是 $O(t(n))$,这些操作的成本都是 $O(t(n))$。将这个单步成本乘以总步数 $t(n)$,再加上初始化的 $O(n)$ 成本,最终得出总模拟时间为 $O(t^2(n))$。
提供一个完整的、形式化的证明,是数学和理论计算机科学严谨性的体现。这个证明不仅仅是给出一个结果,更重要的是展示了如何通过对一个具体的模拟过程进行细致的、最坏情况下的成本分析,来得出一个普适性的复杂度转换定理。它教会了读者一种重要的分析方法。
这就像是用一台老式打字机(单带TM)来排版一份用现代Word处理器(多带TM)编辑好的文档。
你一个人(单带TM)在一条很长的传送带上组装 $k$ 种不同的产品(模拟 $k$ 条磁带)。传送带被分成了 $k$ 段,每段对应一种产品。
📜 [原文20]
接下来,我们考虑非确定性单带图灵机的类似定理。我们证明,任何在此类机器上可判定的语言,都可以在确定性单带图灵机上判定,但需要显著更多的时间。在此之前,我们必须定义非确定性图灵机的运行时间。回想非确定性图灵机是判定机,如果它的所有计算分支都在所有输入上停机。
令 $N$ 是一个非确定性图灵机,它是一个判定机。$N$ 的运行时间是函数 $f: \mathcal{N} \longrightarrow \mathcal{N}$,其中 $f(n)$ 是 $N$ 在任何长度为 $n$ 的输入上的任何计算分支中使用的最大步数,如下图所示。

图 7.10
衡量确定性和非确定性时间
非确定性图灵机的运行时间定义并非旨在与任何实际世界的计算设备相对应。相反,它是一个有用的数学定义,有助于表征一类重要计算问题的复杂度,我们将在稍后演示。
令 $t(n)$ 是一个函数,其中 $t(n) \geq n$。那么,每个 $t(n)$ 时间的非确定性单带图灵机都有一台等价的 $2^{O(t(n))}$ 时间的确定性单带图灵机。
这部分探讨了计算理论中一个更深刻、更核心的关系:非确定性计算与确定性计算之间的效率转换。
1. 引入新问题:确定性 vs. 非确定性
2. 定义NTM的运行时间 (定义 7.9)
3. NTM到DTM的转换定理 (定理 7.11)
本节转向了更深层次的非确定性计算。首先,通过定义计算树的最长分支,为非确定性图灵机 (NTM) 的运行时间给出了一个最坏情况的定义。然后,陈述了里程碑式的定理7.11,该定理指出,任何 $t(n)$ 时间的NTM,都可以被一台 $2^{O(t(n))}$ 时间的确定性图灵机 (DTM) 所模拟。这揭示了在目前已知的模拟方法中,从非确定性到确定性的转换会导致指数级的时间爆炸,与确定性模型内部的多项式级转换形成鲜明对比。
本节的目的是引入非确定性作为一种计算资源,并量化它与确定性计算在效率上的巨大鸿沟。这是为全书最重要的章节之一——NP完全性——进行铺垫。理解这个指数级的时间膨胀,是理解P类和NP类之间可能存在巨大差异的关键,也是理解为何NP完全问题被认为是“难”的根源。
[直觉心-智模型]
解决一个复杂的迷宫问题。
大海捞针。
📜 [原文21]
证明 令 $N$ 是一台在 $t(n)$ 时间内运行的非确定性 TM。我们构造一台确定性 TM $D$,它通过搜索 $N$ 的非确定性计算树来模拟 $N$,如定理 3.16 的证明中所述。现在我们分析该模拟。
在长度为 $n$ 的输入上,$N$ 的非确定性计算树的每个分支的长度最多为 $t(n)$。树中的每个节点最多可以有 $b$ 个子节点,其中 $b$ 是 $N$ 的转移函数给出的合法选择的最大数量。因此,树中叶子的总数最多为 $b^{t(n)}$。
模拟通过广度优先探索这棵树进行。换句话说,它在处理深度 $d+1$ 的任何节点之前,会访问深度 $d$ 的所有节点。定理 3.16 证明中给出的算法在每次访问节点时都从根开始并向下遍历到该节点,效率低下。但消除这种低效率并不会改变当前定理的陈述,所以我们保留它。树中节点的总数小于最大叶子数的两倍,所以我们将其限制为 $O\left(b^{t(n)}\right)$。从根开始并向下遍历到节点所需的时间是 $O(t(n))$。因此,$D$ 的运行时间是 $O\left(t(n) b^{t(n)}\right)=2^{O(t(n))}$。
如定理 3.16 所述,TM $D$ 有三个磁带。根据定理 7.8,转换为单带 TM 最多会将运行时间平方。因此,单带模拟器的运行时间是 $\left(2^{O(t(n))}\right)^{2}=2^{O(2 t(n))}=2^{O(t(n))}$,定理得证。
这是定理7.11的详细证明,它解释了为什么用确定性图灵机(DTM)模拟非确定性图灵机(NTM)会导致指数级的时间爆炸。
1. 模拟策略:搜索计算树
2. 分析计算树的规模
3. 分析模拟的时间成本
4. 转换为单带DTM
该证明通过分析确定性图灵机 (DTM) 对非确定性图灵机 (NTM) 计算树的广度优先搜索 (BFS) 过程,得出了其时间复杂度。证明的关键步骤是:
这最终证明了从非确定性到确定性的转换,在已知的通用模拟中,需要付出指数级的时间代价。
本证明的目的在于为P vs NP问题提供一个数学上的起点。它严格地表明了,如果我们找不到比“暴力搜索所有可能性”更聪明的办法,那么NP问题(能在非确定性多项式时间解决的问题)在确定性计算机上就需要指数时间。这为NP完全理论的重要性奠定了基础:如果我们能为任何一个NP完全问题找到一个确定性的多校式时间算法,那么就等于找到了一个通用的、能避免指数爆炸的“聪明模拟方法”,从而证明P=NP。
你(一个DTM)要去给一个拥有“分身术”的超级英雄(一个NTM)拍一部纪录片。超级英雄在1小时内 ($t(n)$) 完成了拯救世界的任务。
你有一个巨大的家谱,要寻找一位名叫“约翰”的祖先。
这就是DTM模拟NTM时“暴力搜索”的本质。它必须检查由NTM的“选择”所产生的所有指数级的可能性。
这个公式定义了$f(n) = O(g(n))$,即函数 $f(n)$ 的增长速度渐近地不快于函数 $g(n)$ 的常数倍。
这个公式定义了$f(n) = o(g(n))$,即函数 $f(n)$ 的增长速度渐近地严格慢于函数 $g(n)$。
[公式完整性检查]
[字数超越检查]
[段落结构映射检查]
[阅读友好检查]
[[END_OF_RESPONSE]]所有解释内容已全部输出完毕。