【算法】P问题 NP问题 NPC问题 NPH问题的定义与理解

一.前言

二.多项式

三.时间复杂度

四.P问题

五.NP问题

六.NPH问题,NPC问题

七.已经被证明的NPC问题

八.一些具体问题的总结

九.总结

一.前言

       在讨论算法的时候,常常会说到这个问题的求解是个P类问题,或者是NP难问题等等,同时最近上课正在做算法分析与设计关于NP完全问题这一章的作业的时候,发现有很多概念理解的不是很透彻,然后就反复看老师的讲义,在网上查阅各种资料,花了很多时间来弄懂这块的内容。结合老师的课件与算法导论里面的内容,发现书上的概念太正式,定义太标准,不容易很快理解,故自己总结了下,希望能够理解清楚各类问题的本质,不在弄混淆

二.多项式(知道的跳过)

       形如ax^n-bx^n-1+c的式子都是多项式,其中最高次叫x最高次为n的多项式。比如,ax+b=0,ax^2+bx+c=0......很简单......

三.时间复杂度(知道的跳过)

       我们知道在计算机算法求解问题当中,经常用时间复杂度和空间复杂度来表示一个算法的运行效率。空间复杂度表示一个算法在计算过程当中要占用的内存空间大小,这里暂不讨论。时间复杂度则表示这个算法运行得到想要的解所需的计算工作量,他探讨的是当输入值接近无穷时,算法所需工作量的变化快慢程度。时间复杂度并不是表示一个程序解决问题需要花多少时间,而是当问题规模扩大后,程序需要的时间长度增长得有多快。也就是说,对于高速处理数据的计算机来说,处理某一个特定数据的效率不能衡量一个程序的好坏,而应该看当这个数据的规模变大到数百倍后,程序运行时间是否还是一样,或者也跟着慢了数百倍,或者变慢了数万倍。不管数据有多大,程序处理花的时间始终是那么多的,我们就说这个程序很好,具有O(1)的时间复杂度,也称常数级复杂度;数据规模变得有多大,花的时间也跟着变得有多长,这个程序的时间复杂度就是O(n),比如找n个数中的最大值;而像冒泡排序、插入排序等,数据扩大2倍,时间变慢4倍的,属于O(n^2)的复杂度。还有一些穷举类的算法,所需时间长度成几何阶数上涨,这就是O(a^n)的指数级复杂度,甚至O(n!)的阶乘级复杂度。不会存在O(2*n^2)的复杂度,因为前面的那个“2”是系数,根本不会影响到整个程序的时间增长。同样地,O (n^3+n^2)的复杂度也就是O(n^3)的复杂度。因此,我们会说,一个O(0.01*n^3)的程序的效率比O(100*n^2)的效率低,尽管在n很小的时候,前者优于后者,但后者时间随数据规模增长得慢,最终O(n^3)的复杂度将远远超过O(n^2)。我们也说,O(n^100)的复杂度小于O(1.01^n)的复杂度。总结一下就是,常数系数不影响整体的时间复杂度,并且时间复杂度只与增长最快的那一项有关。具体的大小比较可以参考算法之前的学习,各种排序算法的时间复杂度等等。一般地,时间复杂度排序o(1)2,n表示输入的数据个数,o(1)为常数级别)。容易看出,前面的几类复杂度被分为两种级别,其中后者的复杂度都远远大于前者:一种是O(1),O(log(n)),O(n^a)等,我们把它叫做多项式级的复杂度,因为它的规模n出现在底数的位置;另一种是O(a^n)和O(n!)型复杂度,它是非多项式级的,其复杂度计算机往往不能承受。当我们在解决一个问题时,我们选择的算法通常都需要是多项式级的复杂度,非多项式级的复杂度需要的时间太多,往往会超时,除非是数据规模非常小。

四.P类问题

     P类问题:存在多项式时间算法的问题。(P:polynominal,多项式)。前面的内容在正常的学习算法的步骤中应该都已经了解了,理解起来并不会难。以冒泡排序为例,我们知道了,在排序这个大问题里,是可以找到一种时间复杂度为多项式o(n^2)的算法(如冒泡排序法)来求解排序问题的,所以我们说排序问题是一个有多项式时间算法的问题,即P类问题。

五.NP类问题

      NP类问题:能在多项式时间内验证得出一个正确解的问题。(NP:Nondeterministic polynominal,非确定性多项式)。第一,虽然把所需运行时间为O(n^100)的问题作为“难处理问题”也有其合理之处,但实际中却只有极少数问题需要如此高次的多项式时间,且经验表明,一旦某一问题的第一个多项式时间算法被发现后,往往跟着就会发现更为有效的算法。第二,对很多合理的计算模型来说,在一个模型上用多项式时间可解决的问题,在另一个模型上也可以在多项式时间内解决。第三,由于在加法、乘法和组合运算下多项式是封闭的,因此,多项式时间可解问题具有很好的封闭性。反之,非多项式时间一般指指数增长模式,或更复杂模式。很显然,P类问题是NP问题的子集,因为存在多项式时间解法的问题,总能在多项式时间内验证他。注意定义,这里是验证。NP类问题,不知道这个问题是不是存在多项式时间内的算法,所以叫non-deterministic非确定性,但是我们可以在多项式时间内验证并得出这个问题的一个正确解。

       一个有趣的例子:在一个周六的晚上,你参加了一个盛大的晚会。由于感到局促不安,你想知道这一大厅中是否有你已经认识的人。你的主人向你提议说,你一定认识那位正在甜点盘附近角落的女士罗丝。不费一秒钟,你就能向那里扫视,并且发现你的主人是正确的。然而,如果没有这样的暗示,你就必须环顾整个大厅,一个个地审视每一个人,看是否有你认识的人。

       两个有趣的例子:填字游戏是一种最常见的益智纸上游戏,也是NP完全问题之一,游戏一般给出一个矩形的表格。这个表格被分割为若干个大小相同的方格,方格的颜色有白色与黑色两种。白色的方格组成一些交叉的行与列,行列的长度不等。玩家根据题目所提供的有关信息,将答案填入这些行与列之中,每个白色方格中只能填入一个字。一般地说,题目给出的每一条信息就是对应的一行或一列的解题线索。在行与列交叉的地方,玩家必须保证在交叉的方格中填入的字同时满足题目中对行与列的要求。

       著名的NP类问题:旅行家推销问题(TSP)。即有一个推销员,要到n个城市推销商品,他要找出一个包含所有n个城市的环路,这个环路路径小于a。我们知道这个问题如果单纯的用枚举法来列举的话会有(n-1)! 种,已经不是多项式时间的算法了,(注:阶乘算法比多项式的复杂)。那怎么办呢?我们可以用猜的,假设我人品好,猜几次就猜中了一条小于长度a的路径,我画画画画,好的,我得到了一条路径小于a的环路,问题解决了,皆大欢喜。可是,我不可能每次都的那么准,也许我要猜完所有种呢?所以我们说,这是一个NP类问题。也就是,我们能在多项式的时间内验证并得出问题的正确解,可是我们却不知道该问题是否存在一个多项式时间的算法,每次都能解决他(注意,这里是不知道,不是不存在)。就好比说,我RP很好,在程序中需要枚举时,我可以一猜一个准。现在某人拿到了一个求最短路径的问题,问从起点到终点是否有一条小于100个单位长度的路线。它根据数据画好了图,但怎么也算不出来,于是来问我:你看怎么选条路走得最少?我说,我RP很好,肯定能随便给你指条很短的路出来。然后我就胡乱画了几条线,说就这条吧。那人按我指的这条把权值加起来一看,嘿,神了,路径长度98,比100小。于是答案出来了,存在比100小的路径。别人会问他这题怎么做出来的,他就可以说,因为我找到了一个比100 小的解。在这个题中,找一个解很困难,但验证一个解很容易。验证一个解只需要O(n)的时间复杂度,也就是说我可以花O(n)的时间把我猜的路径的长度加出来。那么,只要我RP好,猜得准,我一定能在多项式的时间里解决这个问题。我猜到的方案总是最优的,不满足题意的方案也不会来骗我去选它。这就是NP问题。在这里强调,NP问题不是非P类问题。NP问题是指可以在多项式的时间里验证一个解的问题。NP问题的另一个定义是,可以在多项式的时间里猜出一个解的问题。要深刻理解NP类问题的定义。

       之所以要定义NP问题,是因为通常只有NP问题才可能找到多项式的算法。我们不会指望一个连多项式地验证一个解都不行的问题存在一个解决它的多项式级的算法。信息学中的号称最困难的问题——“NP问题”,实际上是在探讨NP问题与P类问题的关系。所以这就引出了这类讨论的一个千年问题:是否 NP类问题=P类问题?即,是否所有能在多项式时间内验证得出正确解的问题,都是具有多项式时间算法的问题呢?要是解决了这个问题,那岂不是所有的NP问题都可以通过计算机来解决?但是,这个问题并没有被解决,但是在各种讨论中,发现了另外一个重要的问题:NPC类问题。

六.NPC类问题

       为了说明NPC问题,我们先引入一个概念——约化(算法导论里面叫做归约)。所谓问题约化就是,可以用问题B的算法来解决A ,我们就说问题A可以约化成问题B。举个例子,一元一次方程的求解,跟二元一次方程的求解,我们知道,只要能求解二元一次方程,那就可以用二元一次方程的解法来求解一元一次方程,只需要将一元一次方程加上y,并附加一个方程y=0就可以将一元一次方程变形为一个二元一次方程,然后用二元一次方程的解法来求解这个方程。注意,这里二元一次方程的解法会比一元一次的复杂。所以我们说,只需要找到解二元一次方程的规则性解法,那就能用这个规则性解法来求解一元一次方程。从这里也可以看出,约化是具有传递性的,如A约化到B,B约化到C,A就可以约化到C,同时不断约化下去(具有传递性:如果问题A可约化为问题B,问题B可约化为问题C,则问题A一定可约化为问题C),我们会发现一个很惊人的特性,就是他一定会存在一个最大的问题,而我们只需要解决了这个问题,那其下的所有问题也就解决啦!这就是我们所说的NPC问题的概念。“问题A可约化为问题B”有一个重要的直观意义:B的时间复杂度高于或者等于A的时间复杂度。也就是说,问题A不比问题B难。这很容易理解。既然问题A能用问题B来解决,倘若B的时间复杂度比A的时间复杂度还低了,那A的算法就可以改进为B的算法,两者的时间复杂度还是相同。正如解一元二次方程比解一元一次方程难,因为解决前者的方法可以用来解决后者。

       NPC问题:如果所有np问题都能在多项式时间内转化为他,则称该np问题为npc问题(NPC:NP complete又叫NP完全问题)。首先,它得是一个NP问题;然后,所有的NP问题都可以约化到它证明一个问题是 NPC问题也很简单。先证明它至少是一个NP问题,再证明其中一个已知的NPC问题能约化到它,这样就可以说它是NPC问题了。

       NPH问题:又叫NP难问题,他不是一个NP问题,然后所有的NPC问题都可以在多项式时间内转化为他的话,我们就叫他NPH(hard)问题。NP-Hard问题是这样一种问题,它满足NPC问题定义的第二条但不一定要满足第一条(就是说,NP-Hard问题要比 NPC问题的范围广)。NP-Hard问题同样难以找到多项式的算法,但它不列入我们的研究范围,因为它不一定是NP问题。即使NPC问题发现了多项式级的算法,NP-Hard问题有可能仍然无法得到多项式级的算法。事实上,由于NP-Hard放宽了限定条件,它将有可能比所有的NPC问题的时间复杂度更高从而更难以解决。

       在所有的NPC问题中,第一个被证明的是逻辑电路问题。逻辑电路问题是指的这样一个问题:给定一个逻辑电路,问是否存在一种输入使输出为True(可满足性)。一个逻辑电路由若干个输入,一个输出,若干“逻辑门”和密密麻麻的线组成(计算机专业的本科知识,不知道的可以去看电子电路与设计相关的书籍)。若在一个逻辑电路中,无论输入是什么,输出都是False。我们就说,这个逻辑电路不存在使输出为True的一组输入(不可满足性)。具体的证明过程比较复杂,大致就是:第一步,它显然属于NP问题,第二步,并且可以直接证明所有的NP问题都可以约化到它。证明过程相当复杂,其大概意思是说任意一个NP问题的输入和输出都可以转换成逻辑电路的输入和输出(计算机内部也不过是一些 0和1的运算),因此对于一个NP问题来说,问题转化为了求出满足结果为True的一个输入(即一个可行解)。想要了解的可以查阅算法导论的相关章节,讲述的比较清晰。由NPC类问题的定义可以想见,当有了第一个NPC问题之后,接下来会出现越来越对的NPC问题,新NPC问题的证明只需要将其归约到已知的NPC问题上进行证明即可。现在被证明是NPC问题的有很多,任何一个找到了多项式算法的话所有的NP问题都可以完美解决了。因此说,正是因为NPC问题的存在,P=NP变得难以置信。至少现在大部分人都是支持P!=NP的(巴拉巴拉的一堆题外话可以百度各种小故事)。

       最新进展:2010年8月6日,HP LAB的 Vinay Deolalikar 教授宣布证明了P!=NP,证明文章已经发送到该问题各相关领域专家手中,等待检验,在他的主页上,证明过程已经公布(PDF格式共103页),但在8月15日,人们关于论文的看法——即证明不能成立——已经趋于稳定(当然这不能排除大家都同时犯了错误的可能性),随后的发言越来越多地集中于更抽象的层面,并且至今仍在继续。

七.已经被证明的NPC问题

1. 团问题

2.顶点覆盖问题

3.哈密尔顿回路问题

4.旅行商问题

5.子集和问题

       当然有很多,这里只是列举算法导论里面详细证明过得几个NPC问题,具体证明过程可以查阅算法导论,有时间会补上关于这几个NPC问题的证明与分析。

八.一些具体的问题总结

1.证明一个新问题A是NPC问题的方法

a.证明A∈NP;

b.选取一个已知的NPC问题B;

c.构造一个从B到A的变换f;

d.证明f为一个多项式变换。

        这里一个关键的问题是如何选取参照物B和构造多项式变换f。在实际的证明中参照物的选择带有一定的经验性,已知的NPC问题越多越有利。第一个被证明的NPC问题是上文提到过的sat问题(可满足性问题),这个开创性的工作是由COOK完成的,自从他证明了sat问题是NPC问题以来,人们已经发现并证明了数千个NPC问题,如上一节提到的提到的各种问题等。简单来说,证明过程就是两个步骤:

a.首先证明该问题为NP问题,即多项式时间内可验证的。

b.找到一种NPC问题以及一种多项式时间内的规约算法,将NPC问题规约为待证问题。

2. NPC问题一定是NP难问题

3.NP困难问题中包含的一些问题是既不属于NP也不属于P类问题的,一个典型的例子就是第k个最重子集问题。

       关于2和3其实就是关于各类问题的定义的一种理解。综上,在现阶段大多数理论计算机科学家们眼中的P、NP和NPC三者之间的关系是这样的,P和NPC都完全包含在NP内,且P∩NPC=∅。总之,P问题一定是NP问题,NPC问题一定为NP问题,NPC问题也一定为NP-hard问题。但是,NP-hard问题不一定为NPC问题,同样P?=NP也待证明。

4.这类问题这么难以解决,这里只是说难以精确的解决,但是还是可以寻求一些高效率的解决办法。

a.动态规划与分支限界方法:对于许多NP完全问题来说,用动态规划和分支限界方法常可以得到较高的解题效率。
b.概率分析:对于许多NP完全问题,其困难实例出现的概念率很小,因此对这类NP完全问题常可以设计出平均性能很好的算法。
c.近似算法:通常可以设计出解NP完全问题的多项式时间的近似算法,以近似解来代替最优解。
d.启发式算法:在用别的方法都不能奏效时,也可以采用启发式算法来解NP完全问题。这类方法根据具体问题的启发式搜索策略来求问题的解,在实际使用时可能很有效,但有时很难说清楚它的道理。

各类方法都有一些代表的算法,有兴趣的可以查阅资料进行进一步的了解,这里不再详细解释。

九.总结

        一句话,这篇文章只是为了不再混淆P,NP,NPC的概念,方便理解问题,至于具体的证明过程,还是要另外的去了解。有机会会再次更新上文提到过的几种NPC类问题的证明过程。

 

 

你可能感兴趣的:(编程,算法,NP,NPC,P,算法设计与分析)