zoukankan      html  css  js  c++  java
  • P问题、NP问题和NPC问题

    什么是P问题、NP问题和NPC问题

        这或许是众多OIer最大的误区之一。
        你会经常看到网上出现“这怎么做,这不是NP问题吗”、“这个只有搜了,这已经被证明是NP问题了”之类的话。你要知道,大多数人此时所说的NP问题其实都是指的NPC问题。他们没有搞清楚NP问题和NPC问题的概念。NP问题并不是那种“只有搜才行”的问题,NPC问题才是。好,行了,基本上这个误解已经被澄清了。下面的内容都是在讲什么是P问题,什么是NP问题,什么是NPC问题,你如果不是很感兴趣就可以不看了。接下来你可以看到,把NP问题当成是 NPC问题是一个多大的错误。

        还是先用几句话简单说明一下时间复杂度。时间复杂度并不是表示一个程序解决问题需要花多少时间,而是当问题规模扩大后,程序需要的时间长度增长得有多快。也就是说,对于高速处理数据的计算机来说,处理某一个特定数据的效率不能衡量一个程序的好坏,而应该看当这个数据的规模变大到数百倍后,程序运行时间是否还是一样,或者也跟着慢了数百倍,或者变慢了数万倍。不管数据有多大,程序处理花的时间始终是那么多的,我们就说这个程序很好,具有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),O(log(n)),O(n^a)等,我们把它叫做多项式级的复杂度,因为它的规模n出现在底数的位置;另一种是O(a^n)和O(n!)型复杂度,它是非多项式级的,其复杂度计算机往往不能承受。当我们在解决一个问题时,我们选择的算法通常都需要是多项式级的复杂度,非多项式级的复杂度需要的时间太多,往往会超时,除非是数据规模非常小。

        自然地,人们会想到一个问题:会不会所有的问题都可以找到复杂度为多项式级的算法呢?很遗憾,答案是否定的。有些问题甚至根本不可能找到一个正确的算法来,这称之为“不可解问题”(Undecidable Decision Problem)。The Halting Problem就是一个著名的不可解问题,在我的Blog上有过专门的介绍和证明。再比如,输出从1到n这n个数的全排列。不管你用什么方法,你的复杂度都是阶乘级,因为你总得用阶乘级的时间打印出结果来。有人说,这样的“问题”不是一个“正规”的问题,正规的问题是让程序解决一个问题,输出一个“YES”或“NO”(这被称为判定性问题),或者一个什么什么的最优值(这被称为最优化问题)。那么,根据这个定义,我也能举出一个不大可能会有多项式级算法的问题来:Hamilton回路。问题是这样的:给你一个图,问你能否找到一条经过每个顶点一次且恰好一次(不遗漏也不重复)最后又走回来的路(满足这个条件的路径叫做Hamilton回路)。这个问题现在还没有找到多项式级的算法。事实上,这个问题就是我们后面要说的NPC问题。

        下面引入P类问题的概念:如果一个问题可以找到一个能在多项式的时间里解决它的算法,那么这个问题就属于P问题。P是英文单词多项式的第一个字母。哪些问题是P类问题呢?通常NOI和NOIP不会出不属于P类问题的题目。我们常见到的一些信息奥赛的题目都是P问题。道理很简单,一个用穷举换来的非多项式级时间的超时程序不会涵盖任何有价值的算法。
        接下来引入NP问题的概念。这个就有点难理解了,或者说容易理解错误。在这里强调(回到我竭力想澄清的误区上),NP问题不是非P类问题。NP问题是指可以在多项式的时间里验证一个解的问题。NP问题的另一个定义是,可以在多项式的时间里猜出一个解的问题。比方说,我RP很好,在程序中需要枚举时,我可以一猜一个准。现在某人拿到了一个求最短路径的问题,问从起点到终点是否有一条小于100个单位长度的路线。它根据数据画好了图,但怎么也算不出来,于是来问我:你看怎么选条路走得最少?我说,我RP很好,肯定能随便给你指条很短的路出来。然后我就胡乱画了几条线,说就这条吧。那人按我指的这条把权值加起来一看,嘿,神了,路径长度98,比100小。于是答案出来了,存在比100小的路径。别人会问他这题怎么做出来的,他就可以说,因为我找到了一个比100 小的解。在这个题中,找一个解很困难,但验证一个解很容易。验证一个解只需要O(n)的时间复杂度,也就是说我可以花O(n)的时间把我猜的路径的长度加出来。那么,只要我RP好,猜得准,我一定能在多项式的时间里解决这个问题。我猜到的方案总是最优的,不满足题意的方案也不会来骗我去选它。这就是NP问题。当然有不是NP问题的问题,即你猜到了解但是没用,因为你不能在多项式的时间里去验证它。下面我要举的例子是一个经典的例子,它指出了一个目前还没有办法在多项式的时间里验证一个解的问题。很显然,前面所说的Hamilton回路是NP问题,因为验证一条路是否恰好经过了每一个顶点非常容易。但我要把问题换成这样:试问一个图中是否不存在Hamilton回路。这样问题就没法在多项式的时间里进行验证了,因为除非你试过所有的路,否则你不敢断定它“没有Hamilton回路”。
        之所以要定义NP问题,是因为通常只有NP问题才可能找到多项式的算法。我们不会指望一个连多项式地验证一个解都不行的问题存在一个解决它的多项式级的算法。相信读者很快明白,信息学中的号称最困难的问题——“NP问题”,实际上是在探讨NP问题与P类问题的关系。

        很显然,所有的P类问题都是NP问题。也就是说,能多项式地解决一个问题,必然能多项式地验证一个问题的解——既然正解都出来了,验证任意给定的解也只需要比较一下就可以了。关键是,人们想知道,是否所有的NP问题都是P类问题。我们可以再用集合的观点来说明。如果把所有P类问题归为一个集合P中,把所有 NP问题划进另一个集合NP中,那么,显然有P属于NP。现在,所有对NP问题的研究都集中在一个问题上,即究竟是否有P=NP?通常所谓的“NP问题”,其实就一句话:证明或推翻P=NP。
        NP问题一直都是信息学的巅峰。巅峰,意即很引人注目但难以解决。在信息学研究中,这是一个耗费了很多时间和精力也没有解决的终极问
    题,好比物理学中的大统一和数学中的歌德巴赫猜想等。
        目前为止这个问题还“啃不动”。但是,一个总的趋势、一个大方向是有的。人们普遍认为,P=NP不成立,也就是说,多数人相信,存在至少一个不可能有多项式级复杂度的算法的NP问题。人们如此坚信P≠NP是有原因的,就是在研究NP问题的过程中找出了一类非常特殊的NP问题叫做NP-完全问题,也即所谓的 NPC问题。C是英文单词“完全”的第一个字母。正是NPC问题的存在,使人们相信P≠NP。下文将花大量篇幅介绍NPC问题,你从中可以体会到NPC问题使P=NP变得多么不可思议。

        为了说明NPC问题,我们先引入一个概念——约化(Reducibility,有的资料上叫“归约”)。
        简单地说,一个问题A可以约化为问题B的含义即是,可以用问题B的解法解决问题A,或者说,问题A可以“变成”问题B。《算法导论》上举了这么一个例子。比如说,现在有两个问题:求解一个一元一次方程和求解一个一元二次方程。那么我们说,前者可以约化为后者,意即知道如何解一个一元二次方程那么一定能解出一元一次方程。我们可以写出两个程序分别对应两个问题,那么我们能找到一个“规则”,按照这个规则把解一元一次方程程序的输入数据变一下,用在解一元二次方程的程序上,两个程序总能得到一样的结果。这个规则即是:两个方程的对应项系数不变,一元二次方程的二次项系数为0。按照这个规则把前一个问题转换成后一个问题,两个问题就等价了。同样地,我们可以说,Hamilton回路可以约化为TSP问题(Travelling Salesman Problem,旅行商问题):在Hamilton回路问题中,两点相连即这两点距离为0,两点不直接相连则令其距离为1,于是问题转化为在TSP问题中,是否存在一条长为0的路径。Hamilton回路存在当且仅当TSP问题中存在长为0的回路。
        “问题A可约化为问题B”有一个重要的直观意义:B的时间复杂度高于或者等于A的时间复杂度。也就是说,问题A不比问题B难。这很容易理解。既然问题A能用问题B来解决,倘若B的时间复杂度比A的时间复杂度还低了,那A的算法就可以改进为B的算法,两者的时间复杂度还是相同。正如解一元二次方程比解一元一次方程难,因为解决前者的方法可以用来解决后者。
        很显然,约化具有一项重要的性质:约化具有传递性。如果问题A可约化为问题B,问题B可约化为问题C,则问题A一定可约化为问题C。这个道理非常简单,就不必阐述了。
        现在再来说一下约化的标准概念就不难理解了:如果能找到这样一个变化法则,对任意一个程序A的输入,都能按这个法则变换成程序B的输入,使两程序的输出相同,那么我们说,问题A可约化为问题B。
        当然,我们所说的“可约化”是指的可“多项式地”约化(Polynomial-time Reducible),即变换输入的方法是能在多项式的时间里完成的。约化的过程只有用多项式的时间完成才有意义。

        好了,从约化的定义中我们看到,一个问题约化为另一个问题,时间复杂度增加了,问题的应用范围也增大了。通过对某些问题的不断约化,我们能够不断寻找复杂度更高,但应用范围更广的算法来代替复杂度虽然低,但只能用于很小的一类问题的算法。再回想前面讲的P和NP问题,联想起约化的传递性,自然地,我们会想问,如果不断地约化上去,不断找到能“通吃”若干小NP问题的一个稍复杂的大NP问题,那么最后是否有可能找到一个时间复杂度最高,并且能“通吃”所有的 NP问题的这样一个超级NP问题?答案居然是肯定的。也就是说,存在这样一个NP问题,所有的NP问题都可以约化成它。换句话说,只要解决了这个问题,那么所有的NP问题都解决了。这种问题的存在难以置信,并且更加不可思议的是,这种问题不只一个,它有很多个,它是一类问题。这一类问题就是传说中的NPC 问题,也就是NP-完全问题。NPC问题的出现使整个NP问题的研究得到了飞跃式的发展。我们有理由相信,NPC问题是最复杂的问题。再次回到全文开头,我们可以看到,人们想表达一个问题不存在多项式的高效算法时应该说它“属于NPC问题”。此时,我的目的终于达到了,我已经把NP问题和NPC问题区别开了。到此为止,本文已经写了近5000字了,我佩服你还能看到这里来,同时也佩服一下自己能写到这里来。

        NPC问题的定义非常简单。同时满足下面两个条件的问题就是NPC问题。首先,它得是一个NP问题;然后,所有的NP问题都可以约化到它。证明一个问题是 NPC问题也很简单。先证明它至少是一个NP问题,再证明其中一个已知的NPC问题能约化到它(由约化的传递性,则NPC问题定义的第二条也得以满足;至于第一个NPC问题是怎么来的,下文将介绍),这样就可以说它是NPC问题了。
        既然所有的NP问题都能约化成NPC问题,那么只要任意一个NPC问题找到了一个多项式的算法,那么所有的NP问题都能用这个算法解决了,NP也就等于P 了。因此,给NPC找一个多项式算法太不可思议了。因此,前文才说,“正是NPC问题的存在,使人们相信P≠NP”。我们可以就此直观地理解,NPC问题目前没有多项式的有效算法,只能用指数级甚至阶乘级复杂度的搜索。

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

        不要以为NPC问题是一纸空谈。NPC问题是存在的。确实有这么一个非常具体的问题属于NPC问题。下文即将介绍它。
        下文即将介绍逻辑电路问题。这是第一个NPC问题。其它的NPC问题都是由这个问题约化而来的。因此,逻辑电路问题是NPC类问题的“鼻祖”。
        逻辑电路问题是指的这样一个问题:给定一个逻辑电路,问是否存在一种输入使输出为True。
        什么叫做逻辑电路呢?一个逻辑电路由若干个输入,一个输出,若干“逻辑门”和密密麻麻的线组成。看下面一例,不需要解释你马上就明白了。
      ┌───┐
      │ 输入1├─→┐    ┌──┐
      └───┘    └─→┤    │
                          │ or ├→─┐
      ┌───┐    ┌─→┤    │    │    ┌──┐
      │ 输入2├─→┤    └──┘    └─→┤    │
     &
    nbsp;└───┘    │                ┌─→┤AND ├──→输出
                    └────────┘┌→┤    │
      ┌───┐    ┌──┐            │  └──┘
      │ 输入3├─→┤ NOT├─→────┘
      └───┘    └──┘
        这是个较简单的逻辑电路,当输入1、输入2、输入3分别为True、True、False或False、True、False时,输出为True。
        有输出无论如何都不可能为True的逻辑电路吗?有。下面就是一个简单的例子。
      ┌───┐
      │输入1 ├→─┐    ┌──┐
      └───┘    └─→┤    │
                          │AND ├─→┐
                    ┌─→┤    │    │
                    │    └──┘    │  ┌──┐
                    │                └→┤    │
      ┌───┐    │                    │AND ├─→输出
      │输入2 ├→─┤  ┌──┐      ┌→┤    │
      └───┘    └→┤NOT ├→──┘  └──┘
                        └──┘
        上面这个逻辑电路中,无论输入是什么,输出都是False。我们就说,这个逻辑电路不存在使输出为True的一组输入。
        回到上文,给定一个逻辑电路,问是否存在一种输入使输出为True,这即逻辑电路问题。
        逻辑电路问题属于NPC问题。这是有严格证明的。它显然属于NP问题,并且可以直接证明所有的NP问题都可以约化到它(不要以为NP问题有无穷多个将给证明造成不可逾越的困难)。证明过程相当复杂,其大概意思是说任意一个NP问题的输入和输出都可以转换成逻辑电路的输入和输出(想想计算机内部也不过是一些 0和1的运算),因此对于一个NP问题来说,问题转化为了求出满足结果为True的一个输入(即一个可行解)。

        有了第一个NPC问题后,一大堆NPC问题就出现了,因为再证明一个新的NPC问题只需要将一个已知的NPC问题约化到它就行了。后来,Hamilton 回路成了NPC问题,TSP问题也成了NPC问题。现在被证明是NPC问题的有很多,任何一个找到了多项式算法的话所有的NP问题都可以完美解决了。因此说,正是因为NPC问题的存在,P=NP变得难以置信。P=NP问题还有许多有趣的东西,有待大家自己进一步的挖掘。攀登这个信息学的巅峰是我们这一代的终极目标。现在我们需要做的,至少是不要把概念弄混淆了。

    P问题、NP问题、NPC问题的概念及实例证明

    美剧《基本演绎法》(也就是美版“福尔摩斯”)第 2 季第 2 集中,两位研究 NP 问题的数学家被谋杀了,凶手是同行,因为被害者即将证明“P=NP 问题”,她为独吞成果而下了毒手。然而凶手的动机,并不是千禧年大奖难题那100万美元的奖金——解决了 P=NP 问题,就能够破译世界上所有的密码系统,这里面的利益比100万美元多多了。

    剧中只用了一句话来介绍 P=NP 的意义:“能用电脑快速验证一个解的问题,也能够用电脑快速地求出解”。这句过于简单的话可能让大家一头雾水,今天我们就来讲一讲 P vs. NP。

    几种问题及其关系

    首先解释一下什么是NP问题,什么是NP hard问题,什么是NP完全问题。

    • P Problem:这个应该最易理解,就是一个问题可以在Polynominal的时间的得到解决,当然,是对于任意input size。
    • NP Problem:对于一类问题,我们可能没有一个已知的快速的方法得到问题的答案,但是如果给我们一个candidate answer,我们能够在polynominal的时间内验证这个candidate answer到底是不是我们已知问题的答案,这类问题叫做NP problem。所以很显然 P Problem是NP problem的一个子集。
    • NP-hard Problem:对于这一类问题,用一句话概括他们的特征就是“at least as hard as the hardest problems in NP Problem”, 就是NP-hard问题至少和NP问题一样难。
    • NP-Complete Problem:对于这一类问题,他们满足两个性质,一个就是在polynomial时间内可以验证一个candidate answer是不是真正的解,另一个性质就是我们可以把任何一个NP问题在polynomial的时间内把他的input转化,使之成为一个NP-complete问题(即规约)。NP-Complete Problem问题可以互相转换 (在多项式时间内),只要其中一个问题可以在多项式时间内解决,那么其他问题也都将可以在多项式时间内解决。
      这里写图片描述

    规约——一种技巧

    归约(reduction): 规约是证明NP-hard问题的一种常用方法,通常用<=这个符号来表示。如P<=Q,这个就表示P is reducible to Q , or Q is the reduction from P or P is reduced to Q(P问题可以归约到Q问题,or可以把P归约到Q) 。这里的reduction的符号可以当成是 比较难易程度的小于等于号,意味着P至少比Q容易,或者Q至少比P难。
    归约主要做的就是以下两个转化(注意两个转化都要在polynomial的时间内完成)【已知P 是个NP-hard问题,证新问题Q 亦是NP-hard问题】,
    1. 把P的输入转化到Q的输入;
    2. 把Q的输出转化到P的输出。
    下图展示了上述规约过程。其中T1 在多项式时间将 P的输入Pinput 转化成Q的输入Qinput ; T2在多项式时间将 Q的输出Qoutput 转化成P的输出Poutput 。也就是说NP-hard问题P 可以依赖于对问题Q 的解决而解决。那么Q 至少比P要难,即P<=Q
    这里写图片描述

    如何对问题证明

    下面来列出了一些常见的证明问题及其证明套路。

    • 证明NP问题。这个容易,即给你一个结果,你能在polynomial的时间内验证该结果的正确性。
    • 证明NP-hard问题。我们要证明一个问题是NP-hard的时候,我们通常要做的是找到一个已被证明了的NPC问题,并把这个NPC问题归约到该问题上去(即NPC<=NP-hard)。
    • 证明NP-Complete问题。分以下两步:
      1. 第一步证明这个问题属于NP;
      2. 第二步,证明这个问题是NP-hard的。

    下图列出了几个已被发现NP-Complete问题(更全面的NP-Complete问题列表,见链接A compendium of NP optimization problems,以及List of NP-complete problems),及其规约关系。可以看出所有的NP问题都可以规约到SAT(即NP<=SAT),也就是说SAT至少与NP问题一样难,或者如果解决了3SAT问题,所有的NP问题就解决了。同样的,SAT<=3SAT3SAT<=Independent SetIndependent Set<=Vertex Cover OR Clique

    规约关系具有传递性,所以有3SAT<=Vertex CoverNP<=NP-Complete。 事实上,由于NP-Complete NPNP<=NP-Complete,可以推导出 所有的NP-Complete 可以相互规约,也就是所有的NP-Complete都是等价的。
    这里写图片描述

    NP-Complete间的规约例子

    1. 3SAT<=Independent Set

    • 在图G中若顶点集合S满足其中的任意两个顶点之间不存在边,则称S为独立集。The input of Independent Set is a graph G and a number m(独立集问题的两个参数:图G以及独立集的大小m), the problem is to find a set of m pairwise non-adjacent vertices(问题是找到G的一个大小为m的独立集).

    • 转化过程:Given an instance 3SAT problem with m clauses, create an instance (G,m) of Independent Set as follows:

      • Graph G has a triangle(edge or vertex) for each clause, with vertices labeled by the clause’s literals
      • Add edge between any two vertices that represent opposite literals.
      • The goal g is set to the number of clauses.
        The graph below corresponding to (x¯yz¯)(xy¯z)(xyz)(x¯y¯) (clearly m=3)
        这里写图片描述
      • 假设上图有一个最大独立集,则每个三角形中有且仅有一个顶点在该独立集中,设该顶点取值为1,其余顶点取值0,则其肯定是一个满足的3SAT的赋值。
    • 容易证明该规约过程用了多项式时间。

    • 把P的输入转化到Q的输入P的输入是包含m个clause的3SAT表达式;Q的输入当然是转化得到的图形G以及独立集的大小参数g=m
    • 把Q的输出转化到P的输出Q的输出G的一个大小为g的独立集;P的输出是3SAT的一个赋值。假设G中有一个大小为m的独立集,则一定是1)三角形内部三个顶点只能取一个 2)不属于三角形的边所连接的顶点也只取一个。对于每个clause,如果选择了x对应的顶点,则令x=1,如果选择了x¯对应的顶点,则令x¯=1. 则该赋值是满足的。

    2. 3SAT <= Vertex Cover

    • 图的顶点覆盖(有时是节点覆盖)是一组顶点的集合,使得图的每个边缘至少与集合中的一个顶点相连接。在这里Vertex Cover问题是给定图G和点集的个数g,要找到图G的一个大小为g的点覆盖。(我们常说的最小顶点覆盖的问题称为顶点覆盖问题,毫无疑问,它也是一个NP-Complete问题)。
    • 转化过程

      • 按照如下方法构造Graph,对应每一个变量xi,我们构造点二元点对 xix¯i; 对于每一个clause,我们构造三角形的三个顶点,这3个点直接彼此有边,假设这三个点叫A,B,C,我们要建立A,B,C这三个点和该clause的联系:假设我们的clause是 (x1x¯2x¯3) 我们就把x1A连起来,x¯2B连起来,x¯3C连起来。
      • 下面的graph对应于(x1x¯2x¯3)(x1x2x4)
        这里写图片描述
      • 若上图存在最小点覆盖,则将二元点对中在该最小点覆盖中的那一个赋值为1。则该赋值就是一个满足3-SAT的赋值。
    • 假设有m个clause,n个变量。则该规约过程建立了3m+2n个点,n+3m+3m个边。显然可以在多项式时间完成该转换。

    • 把P的输入转化到Q的输入P的输入是包含m个clause的3SAT表达式;Q的输入当然是转化得到的图形G以及覆盖集的大小参数g=2m+n
    • 把Q的输出转化到P的输出Q的输出G的一个大小为g=2m+n的覆盖集;P的输出是3SAT的一个赋值。假设有图G的一个大小为g=2m+n的顶点覆盖,则其中必定包含所有二元点对中的一个点和三角形的两个顶点。对于每个clause对应的三角形的三个边必定被至少一个点覆盖,所以有一个可满足的真值赋值;对于每个二元点对,如果xiS中,则xi=1,如果x¯iS中,则xi=0

    3. 3SAT <= ILP

    • ILP就是Integer Linear Programming,即所有变量都要求是整数。
    • 转化过程
      • 对于 每个clause,我们都对应于ILP中的一个constraint,比如 3SAT中有4个变量,x1x2x3x4, 则ILP中也有同样的这4个变量,并且我们要求他们都是只能取0 或 1。对于一个clause,如(x1x¯2x¯3),我们对应的constraint是 “x1+1x2+1x3=1。很显然了,ILP中的变量选0对应于3SAT中的变量选0,ILP中的变量选1对应于3SAT中的变量选1.
      • 3SAT问题(x1x¯2x¯3)(x1x2x4)对应的ILP如下:
        {x1+1x2+1x3=1x1+x2+x4=1
    • 至于input/output的转换,就如转换过程的描述,异常简单。在此不再叙述。

    4. 3SAT <= Hamiltonian cycle problem

    • 转化过程
      • 对每个变量xi(1in),创建3m+3个顶点,命名为vi,1,vi,2,,vi,3m+3,并且对相邻序号的两个顶点添加互相之间的有向边。如果 xi=1,则形成从左向右的一个路径;如果 x¯i=1,则形成从右向左的一个路径。
      • 对每个1in1,添加四条有向边(vi,1,vi+1,1),(vi,3m+3,vi+1,3m+3),(vi,1,vi+1,3m+3),(vi,3m+3,vi+1,1)
      • 添加两个节点s,t,添加有向边(s,v1,1),(s,v1,3m+3),(vn,1,t),(vn,3m+3,t)。然后再添加有向边(t,s)。这时得到的图中有 hamiltonian cycle,其中一个如下图的虚线所示。
      • 对于每一个clause cj=z1z2z3,创建对应的顶点cj。如果z=xi,则添加有向边(vi,3j,cj)(cj,vi,3j+1); 如果z=x¯i,则添加有向边(cj,vi,3j)(vi,3j+1,cj)。这里1jm,1in。如对子句c=x1x¯2x4 生成如下图中红色所示。如果选择子句中x1=1,则x1对应的路径为从左向右;如果选择x¯2=1,则x2对应的路径为从右到左;如果选择x4=1,则x4对应的 路径为从左到右。这样我们就得到了最终的图G这里写图片描述
      • 若图G有Hamiltonian cycle,则对每一个变量xi对应的路径都是单向的,若为从左到右,则xi=1;若为从右到左,则xi=0。则该赋值肯定是3SAT可满足的。
    • 该转化过程要创建(3m+3)n+m+2个点和(3m+2)×2×n+4(n1)+5+2m个边,是多项式时间的。
    • 把P的输入转化到Q的输入P的输入是包含m个clause,n个变量的的3SAT表达式;Q的输入当然是转化得到的包含(3m+3)n+m+2个点和(3m+2)×2×n+4(n1)+5+2m个边的图形G
    • 把Q的输出转化到P的输出Q的输出G的一个Hamiltonian cycle;P的输出是3SAT的一个赋值。

    5. Subset sum problem <= Partition problem

    • 问题描述:
      • Subset sum problem:given a set (or multiset) of integers T=(t1,t2,,tn), is there a non-empty subset whose sum is k
      • Partition problem: partition problem (or number partitioning) is the task of deciding whether a given multiset W of positive integers can be partitioned into two subsets W1 and W2 such that the sum of the numbers in W1 equals the sum of the numbers in W2.
    • 转化过程:

      • 给定一个子集和的实例为T=(t1,t2,,tn),数k。设tTt=A,则在T的基础上添加两个数{2Ak,A+k},组成一个划分问题的实例W,即
        W={T,2Ak,A+k}.
        wWw=4A
      • 假设找到了W的一个划分W1W2,则有
        wW1w=wW2w=2A
        而且,新添加的两个元素肯定不会同时在W1W2里,否则二者所在的子集的元素和必定大于二者之和3A>2A2Ak所在的子集的其它元素就是一个满足子集和问题的子集。
    • 把P的输入转化到Q的输入P的输入是集合T以及数kQ的输入W={T,2Ak,A+k}.

    • 把Q的输出转化到P的输出Q的输出W的二划分W1W2,有wW1w=wW2wP的输出2Ak所在的子集的其它元素集合。

    6. Clique problem<=Subgraph isomorphism problem

    • 问题描述
      • Clique problem:给定一个图G=(V,E)和整数k,找到G的大小为k的团。
      • Subgraph isomorphism problem:给定两个图G1=(V1,E1),G2=(V2,E2),能否找到G1的一个子图H,使得HG2同构。
    • 转换过程:
      • G1=G,构造G2为包含k个顶点的完全图(即团)。
      • 如果子图同构问题的答案是肯定的,那么枚举G中的任意k个顶点并判定其是否是团,复杂度是多项式的Ckn
    • 把P的输入转化到Q的输入P的输入是图G=(V,E)和整数kQ的输入G1G2
    • 把Q的输出转化到P的输出Q的输出是Yes/No;P的输出G的一个团。

    7. Partition problem <= Knapsack problem

    • 问题描述:
      • Partition problem: partition problem (or number partitioning) is the task of deciding whether a given multiset W of positive integers can be partitioned into two subsets W1 and W2 such that the sum of the numbers in W1 equals the sum of the numbers in W2, i.e.
        tW1t=tW2t=tWt2.
      • Knapsack problem:Given a set of items, each with a weight and a value, determine the number of each item to include in a collection so that the total weight is less than or equal to a given limit and the total value is as large as possible. 给定一个物品集合U={u1,u2,,un},且每个物品有大小s(u)和价值w(u),正整数B和正数K,是否存在子集UU使得
        uUs(u)B,uUw(u)K.
    • 转化过程:
      • For each tW,构造一个item us(u)=w(u)=t, 然后对 B,K添加如下条件
        B=K=uUu2
        那么有
        uUs(u)=uUw(u)=uUu2

    8. Vertex Cover <=Independent Set

    • 问题描述:
      • Vertex Cover:给定一个图G=(V,E)和整数k,找到G的大小为k的点覆盖。
      • Independent Set:给定一个图G=(V,E)和整数k, 找到G的大小为k的独立集。
    • 转化过程:
      • 把参数为G=(V,E)和整数k的点覆盖问题转化为参数为G=(V,E)和整数|V|k的独立集问题。
      • G中有|V|k大小的独立集S,则G中的任意一条边的两端点不可能都在S里。也就是说,G的任意一条边至少与该独立集S之外的其余k个顶点的某一个关联,即该独立集S之外的其余k个顶点是G的一个大小为k的点覆盖。
    • 把P的输入转化到Q的输入P的输入是图G=(V,E)和整数kQ的输入是图G=(V,E)和整数|V|k
    • 把Q的输出转化到P的输出Q的输出G|V|k大小的独立集SP的输出VS.

    9. Independent Set <= Clique problem

    • 问题描述:
      • Independent Set:给定一个图G=(V,E)和整数k, 找到G的大小为k的独立集。
      • Clique problem:给定一个图G=(V,E)和整数k,找到G的大小为k的团。
    • 转化过程:
      • G的大小为k的独立集问题转化为补图G¯的大小为k的团问题。
      • 如果找到补图G¯的大小为k的团,则该团内的任意两个顶点在原图G中没有连接边,即该团的k个顶点是原图G的大小为k的独立集。
    • 把P的输入转化到Q的输入P的输入是图G=(V,E)和整数kQ的输入是补图G¯和整数k
    • 把Q的输出转化到P的输出Q的输出是补图G¯k大小的独立集SP的输出VS.

    10. Hamiltonian cycle problem <= Hamiltonian path problem

    • 问题描述:
      • Hamiltonian cycle problem:a graph cycle (i.e., closed loop) through a graph that visits each node exactly once
      • Hamiltonian path problem: a graph path between two vertices of a graph that visits each vertex exactly once.
    • 转化过程:
      这里写图片描述
      • 在原图G基础上再添加s,w,t三个顶点,任选G中一点u,连接(s,u),(w,t)以及连接u的所有相邻节点与w,生成新图G。如上图所示。
      • 假设新图G有一个Hamiltonian path <s,u,v1,v2,,v,w,t>,由于u,v为相邻节点,故<u,v1,v2,,v>G的Hamiltonian cycle。

    11. Hamiltonian cycle problem <= Traveling salesman problem

    • 问题描述:
      • Hamiltonian cycle problem:a graph cycle (i.e., closed loop) through a graph G=(V,E) that visits each node exactly once。
      • Traveling salesman problem: 即给定一个带权图G=(V,E)和数k,找到一个费用为k的回路。
    • 转化过程:如何得到G=(V,E)和数k
      • V’=V,k=0..
      • E’为完全图的边。还要定义边的权重:
        w(u,v)={0,if(u,v)E1,if(u,v)E
      • 如果G=(V,E)有个费用为k=0的回路,则说明这些边都是在G中存在的,因此是G的一个Hamiltonian cycle problem。

    参考资料

    P、NP、NP-Complete、NP-hard问题

    1 遇到难题怎么办?

    遇到一个问题,通常我们思考的是如何解它。
    于是就有了贪心、分治、动态规划等等算法;但也有一些问题,挠破了头也想不到高效的算法。
    怎么办?

    假如我们已经知道有那么几个问题,这个世界上所有的聪明人都没能找到高效的算法。
    而且我们能把目前的问题通过等价转化的方式,变成这些已知问题的子问题。
    这样就能证明我们不笨。

    这个将一个问题,等价转换成另一个问题的子问题的方式,叫做 归约 (Reduction).

    将问题A归约成问题B的子集

    2 什么是P、NP、NP-Complete和NP-hard

    这些概念都是用来描述一个问题的难度的。即一个问题能否在以上时间内求解,或者验证一个解是否符合一个问题。
    在下面的讨论中,我们假设问题的输入规模是n,那么问题的解决时间,或者验证时间都应该是n的一个函数,记为$f(n)$.

    P, 即Polynomial time,多项式时间。f(n)=a0+a1*n1+a2*n2+a3*n3+…. 。
    意思是说给定一个问题,能在多项式时间内 找到 符合该问题的解。此时,问题的时间复杂度是O(nj).

    那不是多项式时间内能求解的问题,就是NP问题吗? 不是的

    首先,要理解验证解的概念。给定一个问题,我们可能不知道如何解,但如果通过连蒙带猜,得到了一个解。
    我们也可以验证这个解是否满足问题。 NP 就是指能在多项式时间内 验证 一个解是否满足的一类问题。
    所以,P和NP并非补集关系,而是两个完全不同的分类方式。

    显然,所有P类问题都能在多项式时间内验证一个解。因此 P ⊆ NP。
    于是人们就在想NP的问题里面,有最难的问题吗?它会是什么?
    结论是,NP中有 最难 的一类问题。这类问题就是 NP-Complete 问题。
    最难,就意味着所有NP类的问题都能归约到这个问题上。该问题本身也是NP问题。

    所以,NP-Complete问题的形式化定义是: L是NP-Complete问题,当其满足如下两个条件:

    • L ∈ NP
    • 任意L1 ∈ NP, L1 可以归约到 L

    对于只满足条件2,不管满不满足条件1的问题,我们称为NP-hard问题,
    即非常难,且不能在多项式时间内验证解是否正确的问题。(感谢luse兄的指正)

    2.1 NP-hard

    这里在说说NP-hard, NP-hard实际上是“at least as hard as an NP-complete problem”,即这个问题至少和NP完全问题一样难,所以不用满足上面的条件1.

    他们四者的关系,可以用下图描述:

    四者之间的关系

    3 P = NP ????

    计算机科学界最经典,争论最多的一个问题就是: P和NP等价吗?
    实际上,就是说找到一个问题的解的难度,和验证一个解是否满足某个问题的难度相同吗?

    虽然目前,主流认为P是NP的子集,但因为还没办法完全验证这一点,因此不能盖棺定论。
    据说,清华大学的姚期智老师也在从事探索P和NP关系的研究上。
    在针对该问题的最前沿研究上,也是各执一词。参见历史上针对P和VP是否等价的研究结论

  • 相关阅读:
    第二面某知科技的
    面试的提问和大致经过
    抓取菜鸟教程中python内置函数的关键字和链接
    记录下之前写的udp,tcp。很浅显
    python连接mongodb数据库操作
    生成随机字母或数字
    python连接mysql基本操作
    post登录请求
    文件的读写
    request,正则爬虫
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8464339.html
Copyright © 2011-2022 走看看