一.概述

回忆欧拉回路问题,要求找出一条经过图的每条边恰好一次的路径,这个问题是线性可解的。哈密尔顿圈问题是找一个简单圈,该圈包括图的每一个顶点。对于这个问题,现在还没有发现线性算法。

对于有向图的单源无权最短路径问题也是有线性时间可解的,但是对应的最长简单路径问题(longest-simple-path)尚没有发现线性算法。

这些问题的变化,其情况实际上比描述得还要糟。对于这些变种问题不仅不知道线性算法,而且不存在保证以多项式时间运行的已知算法。这些问题的一些熟知算法对于某些情况可能要花费指数时间。

由于相当复杂,我在下面的讨论也只是非正式的,所以可能会存在一些讨论不到位的遗憾。

其实存在大量的重要的问题,它们在复杂性上大体是等价的。这些问题形成了一个类,称为NP-完全(NP-complete)问题。这些NP-完全问题精确的复杂度仍然需要确定并且在计算机理论科学方面仍然是最重要的开放性问题。或者这些问题都有多项式时间算法,或者都没有多项式时间算法。

二.难与易

给问题分类时,第一步要考虑分界。我们看到许多问题都可以用线性时间求解。我们还看到某些O(logN)的运行时间,但是它们或者假定已经做了某些预处理(如输入数据已读入或者数据结构已经建立),或者出现在运算实例中。例如,gcd(最大公因数)算法,当用于两个数M和N时,花费O(logN)的时间。由于这两个数分别由logM和logN个二进制位组成,因此gcd算法实际上花费的时间对于输入数据的量而言是线性的。由此可知,当我们度量运行时间时,我们将把运行时间考虑成输入数据的量的函数。一般来说,不能期望运行时间比线性时间更好。

另一方面,的确存在某些真正困难的问题(以至于它们不可能被解出)。但这并不意味着我们懊恼叹息等着天才来解决。正如实数不足以表示X2<0 的解那样,可以证明的是,计算机不可能解决碰巧发生的每一个问题。这些“不可能”问题,叫做不可判定问题(undecidable problem)

一个特殊的不可判定问题就是停机问题(halting problem)。是否能够使Java编译器拥有一个附加的特性,即不仅能够检查语法错误,而且能够检查所有的无限循环?这似乎是一个比较难的问题,但是我们或许期望,假如某些聪明的程序员花上足够的时间,或许可能编制出这种增强编译器。

这个问题是不可判定的,其直观原因在于,这样的一个程序可能很难检查它自己。由于这个原因,有时候这些问题被叫做递归不可判定的(recursively undecidable)

假如一个无限循环检查程序能够写出,那么它肯定可以用于自检。假设此时我们可以编写这样的一个程序,叫做LOOP。LOOP把一个程序P作为输入并使P自身运行。如果P自身运行时出现循环,则显示短语YES。如果P自身运行终止了,那么自然显示NO。现在,我们换个角度,让LOOP进入无限循环。

当LOOP将自身作为输入会发生什么呢?或者LOOP停止,或者不停止。问题在于,这里面存在罗素悖论。

根据我们的定义,如果P(P)终止,则LOOP(P)进入一个无限循环。设当P=LOOP时,P(P)终止。此时,按照LOOP程序,LOOP(P)应该进入一个无限循环。因此,我们必须让LOOP(LOOP)终止并进入一个无限循环,显然这是不可能的。另一方面,设当P=LOOP时,P(P)进入一个无限循环,则LOOP(P)必然终止,我们得到了同样的一组矛盾。因此可以说,LOOP程序不存在。

三.NP类

NP类是在难度上逊于不可判定问题的类。NP代表非确定性多项式时间(nondeterministic polynomial-time)。确定性机器在每一时刻都在执行一条指令。根据这条指令,机器在去执行某条接下来的指令,这是唯一确定的。而一台非确定性机器对其后的步骤是有选择的。它可以自由进行它想要的任意的选择,如果这些后面的步骤中有一条是导致问题的解,那么它将总是选择这个正确的步骤。因此,非确定性机器有很好的猜测与优化能力。这好像一个很奇怪的模型,因为没有人能够建立这样一台机器,还因为这台机器是对标准计算机的令人难以置信的改进(这时候所有的问题都变成易解的了)。非确定性是非常有用的理论结构。此外,非确定性也不像人们想象的那样强大。比如,即使使用非确定性,不可判定问题仍然是不可判定的。

检验一个问题是否属于NP的简单方法就是将该问题用“是/否(yes/no)问题”的语言描述。如果我们在多项式时间内能够证明一个问题的任意“是”的实例是正确的,那么该问题就是NP类。我们不必担心“否”的实例,因为程序总是进行正确的选择。因此,对于哈密顿圈问题,一个“是”的实例就是图中任意一个包含所有顶点的简单的回路。由于给定一条路径,验证它是否真的是哈密尔顿圈是一件简单的事情,因此哈密尔顿圈问题属于NP。诸如“存在长度大于K的简单路径吗?”这样的问题也可能容易验证从而属于NP。满足这条性质的任何路径均可容易检验。

由于解本身显然提供了验证方法,因此,NP类包括所有具有多项式时间解的问题。人们会想到,既然验证一个问题要比经过计算提出一个答案简单得多,因此在NP中就会存在不具有多项式时间解法的问题。这样的问题至今没有发现,于是,完全有可能非确定性并不是如此重要的改进。

也并不是所有可判定性问题都属于NP。考虑确定一个图是否没有哈密尔顿圈的问题。证明一个图有哈密尔顿圈是相对简单的事情——我们只需要找到一个就可以了。然而却没有人知道如何以多项式时间证明一个图没有哈密尔顿圈。似乎只剩下一个方法,就是枚举并验证。因此,无哈密尔顿圈的问题不知道属不属于NP。

四.NP-完全问题

在已知属于NP的所有问题中,存在一个子集,叫做NP-完全问题,包含了NP中最难的问题。NP-完全问题有一个性质:NP中的任一问题都能够以多项式时间归约成NP-完全问题。

问题 P1可以归约成问题P2 如下:设有一个映射,使得 P1的任何实例都可以变换成P2 的一个实例。求解 P2,然后将答案映射回原始的解答。作为一个例子,考虑把数以十进制输入到一只计算器。将这些十进制数转换成二进制数,所有的计算都以二进制进行。然后,再把最后的答案转变成十进制显示。对于可多项式地归约成P2 的 P1,与变换相联系的所有工作必须以多项式时间完成。

NP-完全问题是最难的NP问题的原因在于,一个NP-完全问题基本上可以用作NP中任何问题的子例,其花费的只不过是多项式的开销量。因此,如果任意NP-完全问题有一个多项式时间解,那么NP中的每一个问题必然都有一个多项式时间解。

假设我们有一个NP-完全问题 P1,并设P2 已知属于NP。再进一步假设 P1多项式地归约成 P2,使得我们可以通过 P2求解 P1只多耗费了多项式时间。由于 P1是NP-完全的,NP中的每一个问题都可以归约成 P1。对于多项式的封闭性,我们看到,NP中的每一个问题均可多项式地归约成P2 。因此, P2是NP-完全的。

五.巡回售货员问题

给定一个完全图G=(V,E),它的边值以及整数K,是否存在一个访问所有顶点并且总值小于等于K的简单回路?

巡回售货员问题是NP-完全的。容易看到,它的解可以用多项式时间检验,当然它属于NP。为了证明它是NP-完全的,我们可以多项式地将哈密尔顿圈问题归约为巡回售货员问题。为此,构造出一个新图G’ , G’ 和G有相同的顶点。对于G‘ 的每一条边(v , w),如果(v , w)∈ G ,那么它就有权1,否则,它的权就是2.我们选取K=|V|。

容易验证,G有一个哈密尔顿圈当且仅当G‘ 有一个总权为|V|的巡回售货员的巡回路线。

现在有许多问题已知是NP-完全问题。为了证明某个新问题是NP-完全问题,必须证明它属于NP,然后构造一个适当的NP-完全问题变换到该问题。

那么第一个NP-完全问题是怎么具体地被证明的呢?由于证明一个问题是NP-完全需要从另一个NP-完全问题变换到它,因此必然存在某个NP-完全问题,对于这个问题不能用上面的思路。第一个被证明的NP-完全问题是可满足性(satisfiability)问题。这个问题把一个布尔表达式作为输入并提问该表达式对各变量的一次赋值取值true。

可满足性问题当然属于NP,因为容易计算一个布尔表达式的值并检查结果是否为真(true)。在1971年,Cook通过直接证明NP中所有问题都可以变换成可满足性问题而证明了NP-完全问题。为此,他用到了对NP中每一个问题都已知的事实:NP中的每一个问题都可以用一台非确定性计算机在多项式时间内求解。计算机的这种形式化模型就是图灵机(Turing machine)。Cook指出这台机器的动作如何能够用一个极其复杂但仍是多项式的冗长的布尔公式来模拟。该布尔公式为真,当且仅当在由图灵机运行的程序对其输入得到一个“是”的答案。

一旦可满足性问题被证明NP-完全,则一大批新的NP-完全问题,包括某些经典的问题,也被证明是NP-完全的。

其实还有还多更加著名的NP-完全问题,比如装箱问题、背包问题、着色问题、团问题。这些NP-完全问题相当广泛,包括来自操作系统、数据库、运筹学、逻辑学等,特别是图论等领域。

 

对NP问题的一点感想的更多相关文章

  1. 学习javascript 的一点感想

    原文:学习javascript 的一点感想 //动态性是指,在一个Javascript对象中,要为一个属性赋值,我们不必事先创建一个字段,只需要在使用的时候做赋值操作即可,如下例:var obj=ne ...

  2. 关于talbeViewCell一点感想

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPa ...

  3. 关于 Bellman-Ford 与 Floyd 算法的一点感想

    在四种常用的最短路算法 Dijkstra, SPFA, floyd, Bellman-Ford 中, Dijks 和 SPFA 的使用较为普遍, 对大多数人来说, 也较为熟悉. 然而, floyd 与 ...

  4. 关于header file、static、inline、variable hides的一点感想

    前言 先看一段代码 #ifndef _INLINE_H #define _INLINE_H template<typename T> static inline T my_max(T a, ...

  5. 对torch的一点感想

    torch是一个基于LuaJIT的科学计算框架,知乎上有个人回答说torch比较适合科研用途, torch与matlab的很多函数很相似

  6. 关于litecoin莱特币挖矿、炒作的一点感想

    比特币早在一.二年前我就听说过这个词了,还自己试过搭设矿机,因为没找到显卡驱动,也没有人一起搞,所以中途放弃了. 后来就不断听说涨了多少倍,总想着都涨这么多了,错了也就错过了. 周二组会,一帮人兴起又 ...

  7. Unity3D 新人学习的一点感想

    想到那里写到那里吧 1.Unity3D的优点大家都知道:组件化.c#语言.可见即所得. 当初刚开始学习的是cocos2dx,c++的货,觉得还是写的不错的,也是国人开发的,真的代码很容易懂,直接看引擎 ...

  8. TreePuzzle 一点感想

    题目链接 这一道题看起来像是一道贪心的水题,但是情况较难考虑周全,比如下图,我就考虑漏了这种情况,点0是可以移动到点1的.然后我就各种奇怪的分类讨论.最终还是没能A,决定放弃治疗. 然后我看了看解答, ...

  9. 关于mac地址的一点感想

    因为怕mac地址冲突导致环路影响,所以修改了本地设备的mac地址.地址修改为 77:77:77:00:22:11, 结果导致 wlan0 下发不下来. 查看配置选项/etc/config/wirele ...

随机推荐

  1. SqlServer PIVOT函数快速实现行转列,UNPIVOT实现列转行

    我们在写Sql语句的时候没经常会遇到将查询结果行转列,列转行的需求,拼接sql字符串,然后使用sp_executesql执行sql字符串是比较常规的一种做法.但是这样做实现起来非常复杂,而在SqlSe ...

  2. 转:C#常用的集合类型(ArrayList类、Stack类、Queue类、Hashtable类、Sort)

    C#常用的集合类型(ArrayList类.Stack类.Queue类.Hashtable类.Sort) .ArrayList类 ArrayList类主要用于对一个数组中的元素进行各种处理.在Array ...

  3. chromedriver与chrome各版本及下载地址

    Selenium从2升级到3之后呢,Selenium 3 相较于2最大的变化就是更加的标准化,可以支持更多的浏览器.那我们做自动化的时候如果用的是selenium3的话,首先要坐的就是下载不同浏览器的 ...

  4. grep 匹配制表符 和 换行符

    使用: [root@dhcp-- ~]# grep $'\n' log.txt [root@dhcp-- ~]# grep $'\t' log.txt 这两个命令 [root@dhcp-- ~]# l ...

  5. leetcode 3. Longest Substring Without Repeating Characters [java]

    idea: 设置一个hashset存储非重复元素 j:遍历s i:最近的一个非重复指针 注意点: 1.Set set = new HashSet<>(); add remove publi ...

  6. ES6对抽象工厂模式与策略模式结合的实践

    这段代码是我在学习了java版的抽象工厂模式后,实现的ES6版抽象工厂,后期大幅修改,加入了策略模式,看起来很多逻辑看似繁琐,不必要写这么多,但是为了练习设计模式,所以才这样做.当所需的工厂种类增多后 ...

  7. Python高级--闭包与装饰器

    前言:在Python中,闭包是一种非常有用的功能!它通常与装饰器一起搭配使用,可以在不改变被装饰函数的功能的基础上,完成更多的功能.如权限认证. 一.如何定义闭包 1.闭包就是两个嵌套的函数,外层函数 ...

  8. Mac svn使用学习-2-服务端

    2.在mac环境下搭建一个SVN服务器环境 1)创建一个名为myCode的仓库——svnadmin命令 格式: svnadmin SUBCOMMAND REPOS_PATH [ARGS & O ...

  9. vagrant特性——基于docker开发环境(docker和vagrant的结合)-1-基本使用

    Docker vagrant提供了使用Docker作为provider(其他的provider有virtualBox.VMware\hyper-V等)的开箱即用支持.这允许你的开发环境由Docker容 ...

  10. leetcode62—Unique Paths

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...