第19章
什么是NP-Hardness
关于算法导论的书(introductory books),包括本系列的1-3部,面对[承受着](sufferfrom)到来自选择上的偏性(selection bias)。这些书聚焦通过聪明、快速可解的算法求解计算问题。毕竟,有什么比一个巧妙的算法捷径(what’s more fun and empoweringto learn than an ingenious algorithmic short-cut)更加有趣和吸引人去学习的事情呢?好的消息是许多基础的和实践相关的问题落入到此种分类之中【即目前种算法用处很广泛)】sorting, graph search,shortest paths, Huffman codes, minimum spanning trees, sequence alignment, andso on.但是,这将是欺骗性(fraudulent/ˈfrɔːdʒələnt/)以只教你这些精选的集合(cherry-picked collection)的问题,而忽略计算上难解性的困扰(spectre/ˈspektə(r)/,脑袋上的一圈圈),困扰着各样的算法设计者和程序员。可悲地是,存着许多重要的计算问题,包括可能出现的项目当中计算性问题,这些问题快速算法并不可解。更糟糕地是,我们不能期望于任何算法上未来的突破而用于此问题,因为被广泛地相信这些问题本质上(intrinsically)是困难的并且通过任何快速算法是不可解的。
刚刚意识到这个残酷的现实(stark reality),两个问题立刻映入到脑海。首先,当NP-Hardness问题出现在你的工作之中,你如何能够识别这种问题,即而相应地调整你的期望值并且浪费时间以寻找一个好地并不存在的算法。第二,当像这样的问题对你的应用来说是十分重要的,你如何调整你的情绪并且算法上的工作能够应用以获取他它们。这本书将告诉你对两个问题以找到贯穿所有问题的答案。
19.1 MST vs.TSP: An Algorithmic Mystery
难计算问题能够找到一些相类似的容易问题并且区分它们(telling them apart)需要一双训练有素的眼睛。搭好舞台,让我们再次约会(rendezvous)熟悉的朋友和他的更高需求的表亲(meet its more demandingcousin,条件更苛刻的表亲):最小生成树和TSP
19.1.1 TheMinimum Spanning Tree Problem最小生成树问题
通过一个令人惊讶的快速算法,一个著名的可解计算问题是MST问题(第15章第3节)
问题:MST
输入:一个连通、无向图
并且对每个边
赋予一个实值
。
输出:图G的一个生成树
,拥有每个边的最小可能之和
。
存在一个图,由点和边组成。边赋予一个属性,图集合的一个特征,所对应边的极值特征。
回想到,一个图
是连接的,贯通的,如果对于每个对(点集内的点
)图包括一个从v 到w 的一条路。G的一个生成树是E的子集T使得子图(V,T)是所有连通和不成环的(acyclic)。
一个图是连通的,就是从任何一点放水,所有的点都是能够流出来的。
树是从一个点放水,只有树的终点有水流出,最便宜的可达距离。
举个例子,
一个图能够拥有生成树的数量是指数级的,于是穷尽搜索方法找到最小图是在问题之外,不可能的。但是MST问题通过聪明快速算法所解决的。
补:最小生成树
Chapter 15 Minimum Spanning Trees
本章应用greedy算法的设计范式于著名的图问题,最小生成树问题。MST问题是研究贪婪算法的一个独特的好地方(uniquely great playground),在这个问题中,几乎任何你能想到的贪婪算法都是正确的。在回顾图并正式定义问题(第15.1节)之后,我们将讨论两个最著名的MST算法——prim算法(第15.2节)和Kruskal算法(第15.5节)。这两种算法都承认各自使用heap和union-find数据结构实现非常快。第15.8节概述了Kruskal算法在机器学习中的应用,用于单链路聚类。
15.1 Problem Definition
最小生成树问题是关于尽可能廉价地连接一堆对象。对象和连接可以代表一些物理的东西,比如计算机服务器和它们之间的通信链接或者可能每个对象都是一个文档的表示(比如,作为单词频率的向量),其连接对应于“相似”文档对。这个问题在包括计算机网络在内的一些应用领域中自然出现(尝试在网上搜索“生成树协议”)和机器学习(见15.8节)。
15.1.1 图
图可以用不同的方式编码,以便在算法中使用。本章假设输入图是用邻接列表表示的,它有一个顶点数组,一个边数组,从每条边到它的两个端点的指针,以及从每个顶点到它的事件边的指针。
19.1.2 TheTraveling Salesman Problem
另一个著名的问题,1-3部分缺失但是在本书之中是十分有名,是旅行商问题(TSP)。它的定义几乎和MST问题一样。随了遍历(简单的循环,跨越所有节点)扮演着生成树的角色以外,
问题:TSP
输入:一个完全无向图
和每个边
有一个实值成本
。
输出:一个
的遍历
(用理论描述就是:找一个路径最小的哈密顿回路(Hamiltonian cycle) 。 哈密顿回路:也称为一笔画问题,就是从一个点出发不重复的走完所有的点,最后在回到出发点。)
正式来讲,一个遍历是一个循环,此循环每个点恰好是一次(exactly once), 由一个点所产生的两个边(incident to)。
QUIZ 19.1
在一个TSP例子中,
,其中
。这里面存在着多少个不同的遍历
。接下来的答案之中,
表示阶层函数(factorial)。
如果其它都不行(if all else fails), TSP可以通过有穷尽枚举所有的遍历(有限个finitely many)并且记住(找到)最小的一个。对于最小的例子,TSP可以通过穷举法来求解。我们是否做得更好?类似MST问题,是否存在一个算法能够神奇地从指数级别TSP的遍历中的干草堆里瞄准(homein)成本最小化的针。尽管两个问题的表面很相似(superficial similarity),TSP似乎要比解决MST问题难得多。
19.1.3 Trying and Failing to Solve the TSP尝试和受挫于求解TSP
我将告诉你一个关于旅行商俗气的故事(cheesy story),但是这将不利于(disservice to )TSP。TSP问题通常是相当基础的。无论何时,你有一缆子按顺序来完成的任务。伴随着执行每个任务所需要的时间或成本属性依赖于之前的任务。你正在谈论伪装的TSP。
举个例子,
19.2 PossibleLevels of Expertise 专业技术的可能等级
一些可计算的问题是要比其它的更加容易。确切地说,NP-Hardness理论的关键是区分问题要么是像MST的从计算上来说是容易问题要么是像TSP的从计算上来说是困难问题。本书的目标是朝向此话题的小白课本和黑带专业知识的读者。本节提供一个关于如何求解接下课本内容的指南,作为你的目标和约束条件的函数。
在识别和解决np难题方面,您目前和希望达到的专业水平是什么?
层级0,NP-Hardness问题是什么?
层级0是总体不能忽视的。你从来没有听到过NP-Hardness问题并且没有意识到许多实际相关的计算的问题被广泛相信通过任何快速算法是无法求解的。如果我们已经完成了工作,本书应该是甚至连层级0的读者也是可达的。
19.3 容易和难问题
由NP-Hardness理论所提出的极简化的“容易”和“难”问题的两元划分:
容易问题:能被多项式时间算法求解;
难问题:在最坏情况下需要指数时间算法
此种NP-Hardness的总结忽略了(overlook)许多重要的微妙之处(Subtlety)。但是从现在开始十年之内,如果你只记得NP-Hardness的意思只有那几个单词,这也是好的。
19.3.1Polynomial-Time Algorithms
为了进入(segue)容易问题的定义,让我们简要(recap)说明许多著名算法的运行时间。
mn 的准确意义是在问题上的特定,但是在所有情况下他们都和所有输入大小相关。从表中关键的信息是所有算法是输入规模的某些多项式的上界,尽管这些算法的运行时间不同。总之,一个多项式时间算法是一个最坏运行时间的
,此处n 表示输入规模而d是一个常数。
19.3.2Polynomial vs. Exponential Time
19.3.3 EasyProblems 容易问题
NP-Hardness理论定义了容易问题为通过多项式时间算法可解的或者等价地来说,或通过一个算法,此算法可解地输入规模(固定的时间预算)随着日益增长的计算力而成一定规模增长。
多项式时间可解问题
一个计算问题是多项式时间可解:如要存在一个多项式时间算法,对任何输入都能正确地求解决此问题。举个例子,本节开始的6个例子均是多项式时间可解的。
技术上来说,输入规模为n,以
时间运行的一个(现实中无用的)算法算作(count as)多项式时间算法并且一个通过诸如此类的算法可解的问题被认为多项式时间可解的。将此声明反过来,如果一个像TSP问题是多项式时间不可以解的。d 无论多大都不可以解。
Courage,Definitions, and Edge Cases
通过多项式时间可解来识别“容易”问题是不完美的。在此理论下,一个问题是可解的(计算上来讲的多项式时间上运行算法)。但是在现实中可能并不是这样,通过一个经验上快速算法,反之亦然。
在定理上,一个问题可解但是在现实
19.3.4 相对难解性
假设我们怀疑一个诸如TSP问题是“不容易的”,意味着通过多项式时间算法是不可解的(而不用考虑多大的多项式)【也就是无论多项式d多大,都不可解】。我们如何积累、收集此类情况的证据呢?多项式时间算法对某些问题(主要是TSP)是不可解的。当然,最令人信服的论据(argument)是密闭的数学证明。但是TSP当前的状态仍然不太明朗(bein limbo):没有人能够找到求解TSP的多项式时间算法;同样,也没有任何一个人发现此算法并不存在的证据。(No one has found apolynomial-time algorithm that solves it, nor has anyone found a proof that nosuch algorithm exists.
尽管我们对算法的用处缺乏理解(deficient understanding),我们如何能够开发一个有助于区分易解性和难解性问题的理论。藏在NP-Hardness理论的背后杰出的终极目标(brilliant conceit)是基于他们的相对难度以划分问题和如果此问题“至少和一大推未解的问题一样难(an overwhelming number of other unsolved problems)就可以宣称此问题为困难。
19.3.5 难问题
在求解TSP时,许多失败的尝试提供了间接证据(旁证,circumstantial evidence),此问题(TSP)在多项式时间内容并不可解。
采用了多个多项式时间算法没有解决TSP问题。于是我们称这些失败的经历间接证明了此问题是个在多项式赶时间内不可解的。
计算问题 多项式时间算法指数级时间算法 难问题容易问题
难问题的弱证据
一个用于TSP的多项式时间算法将求解一个问题,此问题在过去的十年里有无数的聪明的人投入其中。
我们是否能做得更好,意味着建立针对“难解性”更加有力的证据?这就是NP-Hardness所进入的魔力和能力所在。这个伟大的想法是要表明:一个像TSP的问题,至少和许多不同科学领域的大量未解决问题一样困难——事实上,所有的问题,当你看到一个解决方案时,你很快就会知道答案。这样的论证意味着,TSP的一个假设多项式时间算法也会自动解决所有这些其他未解决的问题!
难问题的强证据
对于TSP的多项式时间算法将解决几十年来,成千上万(如果不是成百上千)聪明的头脑一直在努力解决大量的问题。
实际上,NP-Hardness理论表明数以千计的包括TSP在内计算问题是一个问题处于乔装中的变体,都注定要遭受相同的计算命运。如果你想设计一个多项式时间的算法像TSP这样的NP困难问题,你无意中也试图提出这样的算法来解决成千上万的相关问题。我们称一个问题为NP困难,如果有强有力的证据表明它在上述意义上是难解性的:
NP-Hardness (Main Idea)
一个问题是NP困难的,如果它至少与每一个容易识别的解决方案的问题一样困难。
19.3.6 The P != NP Conjecture
也许你听说过p!= NP猜想。到底准确地是什么? 第23.4节给出了精确的数学表述;现在,我们将就于一个非正式的版本,它应该与那些不得不给学生作业打分的人产生共鸣(resonate with)
The P != NPConjecture (非正式版本)
针对一个问题,检验一个存在的解决方案,从根本上来说比自己从零开始想出解决方案要容易得多。猜想中的“P”和“NP”分别指的是从零开始,在多项式时间内求解的问题和那些在多项式时间内可以验证的问题。
例如,检查某人针对Sudoku或KenKen问题所提出的解决方案,似乎比从零开始自己做的更容易。或者,在TSP的环境中,很容易证实有人建议的TS旅行是好的(比如说, 总成本最多1000)。增加了它的边缘的成本;不太清楚你如何很快地从scratch中想出你自己的旅行。因此,直觉强烈地表明P != NP的猜想是正确的。
19.3.7 Provisional Definition of NP-Hardness
NP-Hardness暂时的定义
暂时来讲,我们称一个问题是NP-Hardness,假设P != NP Conjecture是真实的。,如果此问题并不能被多项时间所
19.4 Algorithmic Strategies for NP-Hard Problems
NP难问题的算法策略
假设你已经识别了你的项目成功所依赖的计算问题。可能,你已经花费几周的时间对此问题放大招了(throwing the kitchen sink at it)——所有您所知道的算法设计范例,书中的每一个数据结构,所有免费的原语(all for-free primitive)——但没有一个是有效的。现在你可以解释为什么你数周的努力付诸东流(come to naught)了,但这并不会降低问题对项目的重要性。
19.4.1 General, Correct, Fast (Pick Two)
通用性 正确性 计算速度 选择两个
坏消息是NP-H问题普通存在的(ubiquitous)。现在,一个很可能就潜伏(well be lurking in)在你最新的项目中。好消息是NP-H并不是一个死刑的判决。在现实在NP-H问题(常常但并不总是)被解决。通过足够的资源投入和复杂的算法(sufficientinvestment of resources and algorithmic sophistication),至少大致如此(at least approximately)。
NP-H 向算法设计者提出挑战(throws down the gauntlet/glove),告诉你的期望应该在什么地方。你不应该期望一个用于NP-H问题的通用性目的和总是快速的算法,类似于(akin for)我们在排序、最短路径或序列对齐等问题中看到的问题。除非您足够幸运,只能面对异常小或结构良好的输入,否则您将不得不非常努力地工作来解决问题,并可能做出一些妥协。
哪种类型的妥协呢?NP-H排除了拥有三种期望属性的特征(假设P != NP Conjecture)
三种特征(NP-H问题不能同时拥有全部)
多用途(通用性,General-purpose)适用此问题的各种输入
正确性 对于每个输入,算法能够正确地求解问题
快速性 对于每个输入,算法能够在多项式时间求解。
于是你有三从种方式选择妥协。在通用性、正确性和快速性三个方面妥协。
所有的三个战略都是有用的,都是常见的。