多项式时间归约
学习目标
- 介绍多项式时间归约(polynomial time reduction)的概念, 作为将问题的复杂性相互关联的一种方式
- 看到几个此类归约的例子
- 以3SAT作为归约的基本起点
回想我们在第12章遇到的一些问题:
- 3SAT问题: 判断给定的3合取范式(3CNF formula)是否存在可满足赋值.
- 在图中寻找最长路径.
- 在图中寻找最大割.
- 求解个变量上的二次方程组.
所有这些问题都具有以下特性:
- 这些都是重要问题, 人们投入了大量精力试图为它们寻找更好的算法.
- 这些都是搜索问题, 即我们在某个易于定义的层面上(例如长路径、可满足赋值等)搜索一个“好”的解.
- 每个问题都存在一个平凡的指数时间算法, 即枚举所有可能的解.
- 目前, 对于所有这些问题, 在最坏情况下, 已知的最好算法并不比平凡算法快多少.
在本章及第15章中, 我们将看到, 尽管这些问题表面差异很大, 但我们可以关联它们以及许多其他问题的计算复杂性. 事实上, 上述问题在计算上是等价(computationally equivalent)的, 这意味着解决其中一个问题立刻意味着能解决其他问题. 这种现象被称为完全性( completeness), 是理论计算机科学中一个令人惊讶的发现, 并且我们将看到它具有深远的影响.
本章介绍多项式时间归约的概念, 这是计算复杂性理论, 特别是本书的核心概念. 多项式时间归约是一种将解决一个问题的任务归约(reduce)到另一个问题的方法. 在复杂性理论中, 我们使用归约来论证: 如果第一个问题难以高效解决, 那么第二个问题也必定难以高效解决. 本章中我们将看到几个归约的例子, 而归约将构成我们在第15章要发展的**完全性**理论的基础.
本章描述的所有归约代码可在以下Jupyter笔记本中获取.
在本章中, 我们将看到, 对于在图中寻找最长路径、求解二次方程组以及寻找最大割的每一个问题, 如果存在解决该问题的多项式时间算法, 那么也就存在解决3SAT问题的多项式时间算法. 换句话说, 我们将把解决3SAT的任务归约到上述每一项任务. 另一种理解这些结果的方式是, 如果3SAT问题确实不存在多项式时间算法, 那么这些其他问题也不存在多项式时间算法. 在第15章中, 我们将看到证据(尽管不是证明!)表明上述所有问题都不存在多项式时间算法, 因此都是本质上难解(inherently intractable)的.
问题的形式化定义
出于技术便利性而非实质性的考虑, 我们主要关注判定问题(decision problems, 即答案为“是/否”的问题), 或者说布尔(Boolean)函数(即输出为一比特的函数). 我们将上述问题建模为从到的函数, 方式如下:
3SAT: 3SAT问题可以表述为函数 其输入为一个3CNF公式(即形如的公式, 其中每个是三个变量或其否定的析取), 并满足: 如果存在对变量的某个赋值使其求值为真, 则将映射为 否则映射为 例如:
因为赋值满足该输入公式. 在上面的描述中, 我们假定公式以某种字符串形式表示, 并约定如果输入不是合法的表示, 则函数输出 对于下文所有其他函数, 我们采用相同的约定.
二次方程组: 二次方程组问题对应于函数 它将一组二次方程映射为 如果存在一个赋值满足所有方程; 否则映射为
最长路径: 最长路径问题对应于函数 它将一个图和一个数映射为 如果中存在一条长度至少为的简单路径; 否则将映射为 最长路径问题是著名的Hamiltonian路径问题的推广, 后者判定一个给定的顶点图中是否存在一条长度为的路径.
最大割: 最大割问题对应于函数 它将一个图和一个数映射为 如果中存在一个割能切断至少条边; 否则将映射为
以上所有问题都属于 但是否属于尚属未知. 不过, 我们将在本章中看到, 如果、或中的任何一个属于 那么也属于
多项式时间归约
假设是两个布尔函数. 从到的多项式时间归约(有时简称为 “归约”)是一种表明“不难于”的方式, 其含义是: 如果存在多项式时间算法, 则也存在多项式时间算法.
下面的练习证明了我们的直觉: 意味着“不难于”.
像往常一样, 独立解决这个练习是确保你理解定义 14.1的好方法.
对练习 14.1的解答
对练习 14.1的解答
吹口哨的猪与飞翔的马
从到的归约可以用于两个目的:
- 如果我们已经知道的一个算法, 并且 那么我们可以利用这个归约得到的一个算法. 这是算法设计中广泛使用的工具. 例如, 在12.1.4节中, 我们看到最小割最大流定理(Min-Cut Max-Flow theorem)如何将计算图中最小割的任务归约到计算其中的最大流.
- 如果我们已经证明(或有证据表明)不存在多项式时间算法, 并且 那么该归约的存在允许我们得出结论: 也不存在多项式时间算法. 这是我们在9.4节中看到的“如果猪能吹口哨, 那么马就能飞”的解释. 我们证明, 如果存在一个假设的的高效算法(一只“吹口哨的猪”), 那么由于 就会存在一个的高效算法(一匹“飞翔的马”). 在本书中, 我们经常将归约用于这第二个目的, 尽管两者之间的界限有时是模糊的(见14.10节).
定义 14.1中的概念与我们在不可计算性背景下(例如9.4节)看到的归约之间最关键的差异在于, 为了关联问题的时间复杂度, 我们需要归约是多项式时间可计算的, 而不仅仅是可计算的. 定义 14.1也将归约限制为具有非常特定的形式. 也就是说, 为了证明 我们只允许通过输出来计算的算法, 而不是允许一个使用计算的“神奇黑盒”的通用算法. 这种限制形式对我们来说是方便的, 但人们也定义并使用了更一般的归约(见14.10节).
在本章中, 我们使用归约来关联上述问题的计算复杂度: 3SAT、二次方程组、最大割和最长路径, 以及其他一些问题. 我们将把3SAT归约到后面的问题, 证明高效解决其中任何一个问题都将导致3SAT的高效算法. 在第15章中, 我们将展示相反的方向: 一举将这些问题中的每一个归约到3SAT.
归约的传递性: 既然我们将理解为(就多项式时间计算而言)“在难度上小于等于” 那么如果且 我们期望应有 事实确实如此:
对练习 14.2的解答
对练习 14.2的解答
如果且 那么存在多项式时间可计算的函数和 它们将映射到 使得对于每个 并且对于每个 结合这两个等式, 我们看到对于每个 因此, 为了证明 只需证明映射是多项式时间可计算的. 但是, 如果存在某些常数使得可在时间内计算, 且可在时间内计算, 那么可在时间内计算, 这是多项式时间.
将3SAT归约为零一方程与二次方程
我们现在展示归约的第一个例子. 零一线性方程组问题(Zero-One Linear Equations problem)对应函数 其输入是变量的一个线性方程组集合 输出为当且仅当存在一个对变量赋值值的满足所有方程. 例如, 如果输入是编码以下方程组的字符串
那么 因为赋值满足所有三个方程. 我们特别将注意力限制在变量上的线性方程组, 其中每个方程都具有形式 其中且 1
如果我们问是否存在(实数)的解满足 那么这可以使用著名的Gaussian消元法在多项式时间内解决. 然而, 目前没有已知的高效算法来解决 事实上, 如以下定理所示, 这样的算法将意味着存在解决的算法:
定理 14.1的证明思路
定理 14.1的证明思路
约束可以写成 这是一个线性不等式, 但由于左侧的和最多为三, 我们也可以通过添加两个新变量将其转化为等式, 写作 (我们将为每个约束使用新的变量)最后, 对于每个变量 我们可以通过添加方程来添加一个对应其否定的变量 从而将原始约束映射为 从这个归约中得到的主要技术要点是添加辅助变量的思想, 用以替换像这样不完全符合我们所需形式的方程, 代之以等价的(对于值变量)方程 后者符合我们想要的形式.

图 14.3. 左: 实现到归约的Python代码. 右: 归约的示例输出. 代码在我们的代码库中.
定理 14.1的证明
定理 14.1的证明
为了证明这个定理, 我们需要:
- 描述一个算法 用于将的输入映射为的输入
- 证明该算法在多项式时间内运行.
- 证明对于每个3CNF公式 都有
我们现在就来做这些事. 由于这是我们的第一个归约, 我们将详细阐述这个证明. 不过, 它直接遵循上述证明思路.
归约在算法 14.1中描述, 另见图 14.3. 如果输入公式有个变量和个子句, 算法 14.1会创建一组 包含个方程, 涉及个变量. 算法 14.1先进行步的初始循环(每步花费常数时间), 然后进行另一个步的循环(每步花费常数时间)来创建方程, 因此它在多项式时间内运行.
令为算法 14.1计算的函数. 证明的核心是要证明对于每个3CNF公式 都有 我们将证明分为两部分. 第一部分, 传统上称为完备性(completeness), 旨在证明如果 则 第二部分, 传统上称为可靠性(soundness), 旨在证明如果 则 (“完备性“和“可靠性“的名称来源于将的解视为可满足的“证明“的观点, 在这种情况下, 这些条件对应于第11.1.1节中定义的完备性和可靠性. 然而, 如果你觉得这些名称令人困惑, 你可以简单地将完备性理解为”-实例映射到-实例“的性质, 将可靠性理解为“-实例映射到-实例“的性质.)
我们通过展示两部分来完成证明:
- 完备性: 假设 这意味着存在一个赋值满足 如果我们对的前个变量使用赋值和 那么我们将满足所有形式为的方程. 此外, 对于每个 如果是来自第个子句的方程(是形如或的变量, 具体取决于子句中的文字), 那么我们对前个变量的赋值确保(因为满足 因此我们可以为和赋值, 以确保方程被满足. 因此在这种情况下, 是可满足的, 意味着
- 可靠性: 假设 这意味着方程组有一个满足条件的赋值 那么, 由于方程包含条件 对于每个 都是的否定, 并且, 对于每个 如果具有形式且是的第个子句, 那么相应的赋值将确保 这意味着被满足. 因此在这种情况下
二次方程组
既然我们已经将归约到 那么我们可以利用这一点, 进一步将归约到二次方程组问题(quadratic equations problem). 这对应于函数 其输入是一个次数最多为2的元多项式列表(即它们是二次的), 且多项式均具有整数系数. (后一个条件是为了方便, 可以通过缩放实现.)我们定义等于当且仅当 存在一个解满足方程组
例如, 以下是关于变量的一组二次方程: 你可以验证满足这组方程当且仅当且
定理 14.2的证明思路
定理 14.2的证明思路
利用归约的传递性(练习 14.2), 只需证明即可, 而这一点成立是因为我们可以将方程表达为二次约束 此归约的核心技巧在于, 我们可以利用非线性性来强制连续变量(例如, 取值于的变量)变为离散的(例如, 取值于
定理 14.2的证明
定理 14.2的证明
子集和问题
作为到归约的另一个结果, 我们也可以证明(通过可以归约到子集和问题(subset sum problem)(也称为背包问题knapsack problem). 在子集和问题中, 我们有一个整数列表和一个整数 我们需要判断是否存在某个整数子集, 其和恰好等于 也就是说, 对于 当且仅当存在使得 注意, 子集和问题的输入长度是编码所有数字所需的字符串长度, 大约为 因为使用二进制表示编码一个整数需要位.
定理 14.3的证明思路
定理 14.3的证明思路
我们从进行归约. 直观想法如下. 考虑一个实例 它有个变量和个方程 回想一下, 中的每个方程都具有的形式(左边求和的变量可能多于或少于三个). 对于每个变量 我们可以定义一个向量 其中表示变量出现在方程中, 否则 那么, 方程组存在解当且仅当存在某个集合(对应于那些的使得 其中是方程右边常数项构成的向量(即是第个方程右边的值 现在, 如果我们能够将向量和解释为数字, 那么我们就可以将其视为一个子集和实例. 关键见解是, 我们确实可以通过将向量的第个坐标视为第位数字来将向量看作数字. 由于向量属于 自然的选择是使用二进制基数, 但这在相加时会导致“进位“问题. 因此, 我们使用一个更大的基数 详见以下证明.
定理 14.3的证明
定理 14.3的证明
对于给定的方程组(包含个变量), 我们注意到右边常数项的值永远不会大于(因为最多个在中的变量之和最多为 更具体地说, 如果实例中存在这样的方程, 那么我们可以确定答案为(在归约的上下文中, 可以将其映射到某个没有解的子集和简单实例, 例如且
我们的归约如算法 14.3所述. 对于输入的一个实例(包含个变量 我们输出一个实例 计算如下:
- 其中等于如果变量出现在方程中, 否则等于 数被设为(任何大于的数都可以).
- 其中是方程右边的整数.
换句话说, 和是满足以下条件的整数: 在进制表示下, 的第位数字是当且仅当出现在中, 而的第位数字是的右边常数项.
以下断言将蕴含归约的正确性:
断言: 对于每个 如果 那么满足的方程当且仅当
证明: 证明的关键在于以下简单的加法性质: 当在进制下相加最多个数时, 如果所有这些数的所有位数字都是或 并且 那么对于每个 和数的第位数字就是这些数第位数字的和. 这是因为加法中没有“进位“. 在我们的例子中, 数字在进制下满足此性质, 且 因此对于每个和每个位数字 和的第位数字就仅仅是这些数第位数字的和, 这对应于所有参与第个方程的之和. 当且仅当该方程被满足时, 此和才等于的第位数字.
该断言表明 这正是我们需要证明的.
独立集问题
对于图 独立集(亦称稳定集stable set)是指子集 满足中任意两点间均无边相连(换言之, 每个“单点集”(singleton, 仅包含单个顶点的集合)显然都是独立集, 但寻找更大的独立集可能颇具挑战性. 最大独立集问题(maximum independent set problem, 下文简称“独立集问题”)旨在寻找图中规模最大的独立集. 该问题天然关联于调度问题: 若在相互冲突的两个任务间连边, 则独立集对应于可无冲突同时调度的一组任务. 独立集问题已在多种场景中得到研究, 例如在蛋白质相互作用图中发现结构的算法.
如第14.1节所述, 我们将独立集问题视为函数 输入图与数值 当且仅当包含规模至少为的独立集时输出 现在我们将3SAT归约至独立集问题.
定理 14.4的证明思路
定理 14.4的证明思路
核心思想在于: 为3SAT公式寻找满足赋值, 对应于在避免冲突的前提下满足多个局部约束. 可将“”与“”视为两个冲突事件, 而约束则建立了事件“”“”“”间的冲突, 意味着三者不能同时发生. 由此, 可将解决3SAT问题理解为调度无冲突事件的过程, 当然关键难点仍在于细节处理. 此处的核心技术是将原公式的每个子句映射为一个构件(gadget)——即满足特定性质的小型子图(或更广义的“子实例”). 我们将在多项式时间归约的构造中反复看到这类“构件”的应用.
定理 14.4的证明
定理 14.4的证明
给定包含个变量与个子句的3SAT公式 我们将按如下方式构造包含个顶点的图(参见算法 14.4, 图 14.4为示例, 图 14.5为Python代码实现):
- 中的子句具有形式 其中为_文字变量_(变量或其否定). 对每个这样的子句 我们在中添加三个顶点, 并分别标记为、和 同时在这三个顶点两两之间添加边, 使其构成三角形. 由于包含个子句, 图将包含个顶点.
- 除上述边外, 我们还在所有形式为和的顶点对间添加边, 其中与是冲突的文字变量. 即若存在使得而(或反之), 则在与间添加边.
基于构造的算法耗时多项式级别: 包含两个循环, 第一个循环需要步, 第二个循环需要步(见算法 14.4). 因此要证明定理, 只需证可满足当且仅当包含个顶点的独立集. 现证明该等价关系的两个方向:
第一部分: 完备性. “完备性”方向需证明: 若存在满足赋值 则存在包含个顶点的独立集 现证明如下:
假设存在满足赋值 则对的每个子句 文字变量中至少有一个在赋值下计算为真(否则无法满足 我们构造包含个顶点的集合 对每个子句 选取一个形式为且在下计算为真的顶点加入(若同一子句存在多个满足条件的顶点, 则任选其一).
我们断言是独立集. 假设存在中的顶点对和之间有边相连. 由于我们从每个子句对应的三角形中仅选取了一个顶点, 必有 此时和之间存在边的唯一可能是与为冲突文字变量(即存在使且 但这样它们在赋值下不可能同时计算为真, 与集合的构造方式矛盾. 完备性得证.
第二部分: 可靠性. “可靠性”方向需证明: 若存在包含个顶点的独立集 则存在满足赋值 现证明如下:
假设存在包含个顶点的独立集 我们按如下规则为的变量定义赋值
- 若包含形式为的顶点, 则令
- 若包含形式为的顶点, 则令
- 若不包含上述两种形式的顶点, 则可任意取值(为明确起见取
首先注意到是良定义的: 上述规则不会相互冲突, 不会要求同时取和 这是因为是独立集, 若其包含形式的顶点, 则不可能包含形式的顶点.
现断言是的满足赋值. 由于是独立集, 在每个对应于子句的三角形中, 至多包含一个顶点. 又因 故在每个此类三角形中恰包含一个顶点. 对的每个子句 若是在对应三角形中的顶点, 则根据的定义, 文字变量必计算为真, 这意味着满足该子句. 因此满足的所有子句, 即满足赋值的定义.
定理14.8证毕.
归约的若干练习与结构剖析
归约可能令人困惑, 而通过练习是增进对其熟悉度的绝佳方式. 这里提供这样一个示例. 一如既往, 我建议你在查看解答之前先自行尝试.
图中的一个顶点覆盖(vertex cover)是顶点的一个子集 使得每条边都至少与中的一个顶点相连(见图 14.6). 顶点覆盖问题的任务是, 给定图和一个数 判断图中是否存在一个最多包含个顶点的顶点覆盖. 形式化地说, 这是函数 使得对于每个和 当且仅当存在一个顶点覆盖满足
证明
对练习 14.3的解答
对练习 14.3的解答
关键观察是: 如果是一个触及所有顶点的顶点覆盖, 那么不存在边使得的两个端点都在集合中, 反之亦然. 换言之, 是顶点覆盖当且仅当是独立集. 由于的大小是 我们看到多项式时间映射(其中是的顶点数)满足 这意味着这是一个从独立集到顶点覆盖的归约.
对练习 14.4的解答
对练习 14.4的解答
如果是一个图, 我们用表示它的补图(complement), 该图具有相同的顶点集 并且对于任意不同的 边出现在中当且仅当该边不出现在中.
这意味着对于任意集合 是中的独立集当且仅当是中的一个团. 因此对于每个 由于映射可以被高效计算, 这就产生了一个归约 此外, 由于 这也就产生了另一个方向的归约.
支配集
在上述两个例子中, 归约几乎是“平凡的“: 从独立集到顶点覆盖的归约仅仅将数改为 而从独立集到团的归约则将边翻转为非边, 反之亦然. 下面的练习需要一个更有趣一些的归约.
图中的一个支配集(dominating set)是顶点的一个子集 使得每个都是中某个的邻居(见图 14.7). 支配集问题的任务是, 给定图和数 判断是否存在一个支配集满足 形式化地说, 这是函数 使得当且仅当中存在一个最多包含个顶点的支配集.
证明
对练习 14.5的解答
对练习 14.5的解答
既然我们知道 利用传递性, 只需证明 如图 14.7所示, 支配集与顶点覆盖不是同一个概念. 然而, 我们仍然可以关联这两个问题. 思路是将图映射为图 使得中的顶点覆盖能够转化为中的支配集, 反之亦然. 我们的做法是: 在中包含的所有顶点和边, 但对于中的每条边 我们还向添加一个新顶点并将其同时连接到和 设为中孤立顶点的数量. 证明背后的思路是: 我们可以通过向添加所有孤立顶点, 将中大小为的顶点覆盖转化为中大小为的支配集; 而且, 我们可以将中每个大小为的支配集转化为中的顶点覆盖. 现在我们给出细节.
算法描述: 给定顶点覆盖问题的一个实例 我们将映射为支配集问题的一个实例 具体如下(Python实现见图 14.8):
算法 14.5在多项式时间内运行, 因为循环需要步, 其中是边的数量, 每一步可以在常数或至多线性时间内实现(取决于图的表示方式). 计算顶点图中孤立顶点的数量, 如果用邻接矩阵表示, 则可以在时间内完成; 如果用邻接表表示, 则可以在时间内完成. 无论如何, 该算法在多项式时间内运行.
为了完成证明, 我们需要证明对于每个 如果是算法 14.5在输入上的输出, 那么 我们将证明分为两部分. 完备性部分是指如果那么 可靠性部分是指如果那么
完备性: 假设 那么存在一个最多包含个顶点的顶点覆盖 设是中孤立顶点的集合, 是它们的数量. 那么 我们声称是中的一个支配集. 确实, 对于的每个顶点 有三种情况:
- 情况1: 是中的孤立顶点. 这种情况下在中.
- 情况2: 是中的非孤立顶点, 因此存在的某条边 这种情况下, 由于是顶点覆盖, 中必须有一个在中, 因此或的一个邻居必须在中.
- 情况3: 是这种形式的顶点, 其中是中的两个邻居. 但由于是顶点覆盖, 中必须有一个在中, 因此包含的一个邻居.
我们得出结论: 是中一个大小不超过的支配集, 因此在假设的条件下,
可靠性: 假设 那么中存在一个大小不超过的支配集 对于图中的每条边 如果包含顶点 那么我们将这个顶点移除并用代替它. 仅有的两个邻居是和 并且由于既是的邻居也是的邻居, 用替换保持了它是一个支配集的性质. 此外, 这个改变不会增加的大小. 因此, 经过这个修改后, 我们可以假设是一个最多包含个顶点且不包含任何形式顶点的支配集.
设是中的孤立顶点集合. 这些顶点在中也是孤立的, 因此必须包含在中(孤立顶点必须包含在任何支配集中, 因为它没有邻居). 我们令 那么 我们声称是中的一个顶点覆盖. 确实, 对于中的每条边 根据支配集性质, 要么顶点 要么它的某个邻居必须在中. 但由于我们确保了不包含任何形式的顶点, 那么或必须有一个在中. 这表明是中一个大小不超过的顶点覆盖, 从而证明
算法 14.5及我们目前所见其他归约的一个推论是: 如果(即支配集存在多项式时间算法), 那么(即存在多项式时间算法). 根据逆否命题, 如果不存在多项式时间算法, 那么支配集也不存在.
归约的结构剖析
练习 14.5中的归约很好地展示了归约的组成部分. 一个归约包含四个部分:
- 算法描述: 这部分描述算法如何将输入映射为输出. 例如, 在练习 14.5中, 就是描述我们如何将顶点覆盖问题的一个实例映射为支配集问题的一个实例
- 算法分析: 仅仅描述算法如何工作是不够的, 我们还需要解释为什么它能工作. 具体来说, 我们需要提供一项分析, 解释为什么该归约既是高效的(即在多项式时间内运行)又是正确的(满足对每个都有 具体而言, 对一个归约的分析包含以下部分:
- 高效性: 我们需要证明在多项式时间内运行. 在遇到的大多数归约中, 这部分是直截了当的, 因为我们通常使用的归约只涉及常数数量的嵌套循环, 每个循环包含常数数量的操作. 例如, 练习 14.5中的归约仅仅是枚举输入图的边和顶点.
- 完全性: 在证明的归约中, 完全性条件是指: 对于每个 如果 那么 我们通常通过将证明的“证书/解“映射为证明的解的方式来构造归约, 以确保此条件成立. 例如, 在练习 14.5中, 我们构造图时, 使得对于中的每个顶点覆盖 集合(其中是孤立顶点)将是中的一个支配集.
- 可靠性: 此条件是指, 如果则 或者(取其逆否命题)如果则 这有时是直接的, 但通常比完全性条件更难证明, 并且在更高级的归约中(例如定理 14.4中的归约), 证明可靠性是分析的主要部分. 例如, 在练习 14.5中, 为了证明可靠性, 我们需要证明对于图中的每一个支配集 在图中存在一个大小至多为的顶点覆盖(其中是孤立顶点的数量). 这具有挑战性, 因为支配集可能不一定是我们“心中所想“的那个. 具体来说, 在上面的证明中, 我们需要修改以确保它不包含形如的顶点, 并且重要的是要证明这个修改仍然保持是一个支配集的性质, 同时不会使其变大.
每当你需要提供一个归约时, 你应该确保你的描述包含所有这些部分. 虽然有时将归约的描述与其分析交织在一起很诱人, 但通常将两者分开, 并将分析分解为高效性、完全性和可靠性三个部分会更清晰.
从独立集归约到最大割
我们现在要证明独立集问题可以归约到最大割问题(maximum cut problem), 这里将最大割问题建模为函数 该函数在输入一对时, 当且仅当包含一个至少包含条边的割时输出 由于两者都是图问题, 从独立集到最大割的归约会将一个图映射到另一个图, 但正如我们将要看到的, 输出图不一定与输入图具有相同的顶点或边.
定理 14.5的证明思路
定理 14.5的证明思路
我们将把一个图映射到一个图 使得中的一个大的独立集成为中割开许多边的划分. 我们可以将中的一个割看作将每个顶点着色为“蓝色“或“红色“. 我们将添加一个特殊的“源“顶点 将其连接到所有其他顶点, 并且不失一般性地假设它被着为蓝色. 因此, 我们着红色的顶点越多, 割开的来自的边就越多. 现在, 对于原始图中的每一条边 我们将添加一个特殊的“构件“, 这是一个包含、、源点和另外两个额外顶点的小子图. 我们设计这个构件的方式是, 如果红色顶点在中不是独立集, 那么中对应的割将被“惩罚“, 即它不会割开那么多边. 一旦我们为自己设定了这个目标, 就不难找到一个能实现它的构件——参见下面的证明. 这里的核心技巧再次是使用(这次是稍微更巧妙一点的)构件.
定理 14.5的证明
定理 14.5的证明
我们将一个具有个顶点和条边的图转化为一个具有个顶点和条边的图 方式如下(另见图 14.10). 图包含的所有顶点(但不包含它们之间的边!), 此外还具有:
- 一个特殊的顶点 它连接到的所有顶点.
- 对于每一条边 两个顶点 使得连接到 连接到 并且我们将边添加到中.
通过证明包含一个大小至少为的独立集当且仅当有一个割开至少条边的割, 即可得出定理 14.5. 我们现在证明这个等价关系的两个方向:
第1部分: 完备性: 如果是中一个大小为的独立集, 那么我们可以定义为中具有以下形式的割: 我们让包含的所有顶点, 并且对于中的每一条边 如果且 那么我们将添加到 如果且 那么我们将添加到 如果且 那么我们将和都添加到 (我们不需要担心和都在中的情况, 因为它是一个独立集.)我们可以验证, 在所有情况下, 从到其补集在对应于的构件中的边数将是四条(参见图 14.11). 由于不在中, 我们还有条从到的边, 总共条边.
第2部分: 可靠性: 假设是中的一个割, 割开了至少条边. 我们可以假设不在中(否则我们可以将“翻转“为其补集 因为这不会改变割的大小). 现在让是中对应于原始顶点的顶点集合. 如果是一个大小为的独立集, 那么我们就完成了. 情况可能并非总是如此, 但我们将看到, 如果不是独立集, 那么它的大小也大于 具体来说, 我们定义为中完全包含在内的边的集合, 并令(即, 如果是一个独立集, 则 根据我们构件的性质, 我们知道对于的每一条边 当和都在中时, 我们最多能割三条边, 否则最多能割四条边. 因此, 割开的边数满足 由于 我们得到 现在, 我们可以通过遍历内部的条边中的每一条, 并从中移除该边的一个端点, 从而将转化为一个独立集 得到的集合是图中的一个大小为的独立集, 从而完成了可靠性条件的证明.

图 14.12. 从独立集到最大割的归约. 右侧是实现该归约的Python代码. 左侧是归约应用的一个示例输出, 我们将其应用于通过对3CNF公式运行定理 14.4的归约得到的独立集实例.
从3SAT归约到最长路径
注意: 本节内容还有点凌乱; 可以跳过它, 或者只阅读而不深入证明细节. 证明出现在Sipser书籍的7.5节.
计算机科学中最基本的算法之一是Dijkstra算法, 用于查找两个顶点之间的最短路径. 我们现在证明, 相比之下, 最长路径问题的高效算法将意味着3SAT存在多项式时间算法.
定理 14.6的证明思路
定理 14.6的证明思路
def TSAT2LONGPATH(φ):
"""将 3SAT 归约为 LONGPATH"""
def var(v): # 返回变量以及指示是是否带有否定的True/False
return int(v[2:]),False if v[0]=="¬" else int(v[1:]),True
n = numvars(φ)
clauses = getclauses(φ)
m = len(clauses)
G =Graph()
G.edge("start","start_0")
for i in range(n): # 为每个变量添加2条长度为m的路径
G.edge(f"start_{i}",f"v_{i}_{0}_T")
G.edge(f"start_{i}",f"v_{i}_{0}_F")
for j in range(m-1):
G.edge(f"v_{i}_{j}_T",f"v_{i}_{j+1}_T")
G.edge(f"v_{i}_{j}_F",f"v_{i}_{j+1}_F")
G.edge(f"v_{i}_{m-1}_T",f"end_{i}")
G.edge(f"v_{i}_{m-1}_F",f"end_{i}")
if i<n-1:
G.edge(f"end_{i}",f"start_{i+1}")
G.edge(f"end_{n-1}","start_clauses")
for j,C in enumerate(clauses): # 为每个子句添加构件
for v in enumerate(C):
i,sign = var(v[1])
s = "F" if sign else "T"
G.edge(f"C_{j}_in",f"v_{i}_{j}_{s}")
G.edge(f"v_{i}_{j}_{s}",f"C_{j}_out")
if j<m-1:
G.edge(f"C_{j}_out",f"C_{j+1}_in")
G.edge("start_clauses","C_0_in")
G.edge(f"C_{m-1}_out","end")
return G, 1+n*(m+1)+1+2*m+1
定理 14.6的证明
定理 14.6的证明
我们构造一个从蜿蜒到的图 如下所示. 在之后, 我们添加一系列个长循环. 每个循环有一条“上部路径“和一条“下部路径“. 一条简单路径不能同时走上部路径和下部路径, 因此它需要恰好选择其中一条才能从到达
我们的意图是, 图中的一条路径将对应于一个赋值 其意义是: 在第个循环中走上部路径对应于赋 走下部长路径对应于赋 当我们蜿蜒穿过所有对应于变量的个循环到达后, 我们需要穿过个“障碍“: 对于每个子句 我们将有一个由一对顶点组成的小构件, 它们之间有两条路径. 例如, 如果第个子句的形式为 那么一条路径会穿过对应于的下部循环中的一个顶点, 一条路径会穿过对应于的上部循环中的一个顶点, 第三条路径会穿过对应于的下部循环中的一个顶点. 我们看到, 如果我们在第一阶段按照一个可满足赋值走, 那么我们将能够找到一个空闲的顶点从旅行到 我们将链接到 链接到 等等, 并将链接到 因此, 一个可满足赋值将对应于一条从到的路径, 该路径穿过每个对应于变量的循环中的一条路径, 以及每个对应于子句的循环中的一条路径. 我们可以使对应于变量的循环足够长, 以至于我们必须走完每个循环中的整条路径, 才有可能获得一条与可满足赋值相对应的那样长的路径. 但如果我们这样做, 那么能够到达的唯一方式就是我们走过的路径对应于一个可满足赋值, 否则我们将有一个子句 在该子句中, 我们无法在不使用之前已用过的顶点的情况下从到达
关系总结
我们已经证明存在若干函数 可对之证明形如“若则”的命题. 因此, 即便仅为这些问题之一设计出多项式时间算法, 也将导致获得的多项式时间算法(参见图 14.16). 在第15章中, 我们将对这些函数证明逆命题(“若则”), 从而得出它们与具有等价复杂性(equivalent complexity)的结论.
- 众多看似无关的计算问题的计算复杂性可通过归约相互关联.
- 若 则的多项式时间算法可转化为的多项式时间算法.
- 等价而言, 若且不存在多项式时间算法, 则亦不存在.
- 我们已发展多种技术证明对于重要函数有 有时可利用归约的传递性: 若且 则
习题
参考书目
学界定义了多种归约概念. 定义 14.1所述概念常被称为映射归约(mapping reduction)、多到一归约(many to one reduction)或Karp归约.
极大独立集(maximal independent set, 与最大独立集maximum independent set相对)是寻找独立集的“局部极大解”任务: 即一个无法再添加顶点而不破坏独立性的独立集(此类集合称为顶点覆盖). 与寻找最大独立集不同, 极大独立集可通过贪心算法高效求得, 但此类局部极大解可能远小于全局最大解.
独立集到最大割的归约取材自相关讲义. 十二面体Hamiltonian路径图像由Christoph Sommer提供.
我们曾提及算法设计所用归约与证明难解性所用归约间的界限有时是模糊的. SAT求解器领域(参见(Gomes, Kautz, Sabharwal, Selman, 2008))是绝佳例证: 该领域研究者利用SAT算法(虽在最坏情况下需指数时间, 但在实际诸多实例中远快于此)结合形如的归约, 为其他目标函数设计算法.
1: 如果你熟悉矩阵表示法, 你可能会注意到这样的方程可以写成的形式, 其中是一个元素为的矩阵, 且













