关于计算机

1.CPU

中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心(Control Unit)。它的功能主要是解释计算机指令以及处理计算机软件中的数据。
中央处理器主要包括运算器(算术逻辑运算单元,ALU,Arithmetic Logic Unit)和高速缓冲存储器(Cache)及实现它们之间联系的数据(Data)、控制及状态的总线(Bus)。它与内部存储器(Memory)和输入/输出(I/O)设备合称为电子计算机三大核心部件。

2.关于文件删除恢复

计算机是通过覆盖文件来达到删除文件的目的。计算机即使回收站清空,文件只是被标记为删除,在不做任何操作时不会被覆盖,仍可能通过回复软件找回。

3.关于复制粘贴

1.剪切板相当于一个中间储存柜,
2.需复制的内容(文字、图片、多媒体、文件、文件夹等)在选择“复制”功能后,数据就暂时保存在这里,
3.在进行下一步“粘贴”操作时,操作系统就将保存在剪切板内的数据进行复制并保存到指定的位置。这就是复制粘贴的原理。
4.在下一次执行“复制”功能后,上一次保存在剪切板内的数据就被新复制的内容所取代,如果没有执行过“复制”功能,则第一次复制的内容在关机前都一直存在剪切板里,关机后就没有了,因为剪切板只是临时性的。

关于计算机语言

1.关于汇编语言:

是一种与具体硬件相关的程序设计语言
在编写复杂程序时,相对于高级语言而言代码量较大,且不易调试
可以直接访问寄存器、内存单元、以及I/O端口

2.C,C++,Pascal语言

C++语言为支持面向对象的高级语言,C语言,Pascal语言是面向结构的高级语言 。
C++不是历史上第一个支持面向对象的语言。

关于计算机发展史

1.摩尔定律

摩尔定律(Moore’s law)是由英特尔创始人之一戈登•摩尔(Gordon Moor)提出来的。根据摩尔定律,在过去几十年一级在可预测的未来纪念,单块集成电驴的集成度大约每18个月翻一番
补充:
摩尔定律是由英特尔(Intel)创始人之一戈登·摩尔(Gordon Moore)提出来的。其内容为:当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。换言之,每一美元所能买到的电脑性能,将每隔18-24个月翻一倍以上。这一定律揭示了信息技术进步的速度。

2.不同种类的计算机

从ENIAC到当前最先进的计算机,冯•诺依曼体系结构始终占有重要地位。冯诺依曼提醒结构的核心内容是采用存储程序和程序控制原理。
1956年诺贝尔物理学奖手语肖克利、巴丁和布拉顿,以表彰他们对半导体的研究和晶体管效应的发现。
1946年诞生于美国宾夕法尼亚大学的ENIAC属于电子管计算机

关于操作系统:

Photoshop不属于操作系统.

关于互联网

1.OSI模型

第7层 应用层

提供为应用软件而设的界面,以设置与另一应用软件之间的通信。例如: HTTP,HTTPS,FTP,TELNET,SSH,SMTP,POP3等。

第6层 表示层

把数据转换为能与接收者的系统格式兼容并适合传输的格式。

第5层 会话层

负责在数据传输中设置和维护电脑网络中两台电脑之间的通信连接。

第4层 传输层

把传输表头(TH)加至数据以形成数据包。传输表头包含了所使用的协议等发送信息。例如:传输控制协议义(TCP) 等。

第3层 网络层

决定数据的路径选择和转寄,将网络表头(NH)加至数据包,以形成分组。网络表头包含了网络数据。例如:互联网协议(IP) 等。

第2层 数据链路层

负责网络寻址、错误侦测和改错。当表头和表尾被加至数据包时,会形成了帧。数据链表头(DLH)是包含了物理地址和错误侦测及改错的方法。数据链表尾(DLT)是一串指示数据包末端的字符串。例如以太网、无线局域网(Wi-Fi)和通用分组无线服务(GPRS)等。

第1层 物理层

在局部局域网上传送帧,它负责管理电脑通信设备和网络媒体之间的互通。包括了针脚、电压、线缆规范、集线器、中继器、网卡、主机适配器等

2.几个网络协议

HTTP(HyperText Transfer Protocol超文本传输协议是互联网上应用最为广泛的一种网络协议)
HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer以安全为目标的HTTP通道,简单讲是HTTP的安全版)
FTP(File Transfer Protocol文件传输协议)
TELNET(Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式)
SSH(Secure Shell安全外壳协议)
SMTP(Simple Mail Transfer Protocol简单邮件传输协议)
POP3(Post Office Protocol - Version 3邮局协议版本3)

3.网站域名&&IP地址

IP地址

IP地址是指互联网协议地址。
IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。

域名

介绍

域名是由一串用“点”分隔的字符组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置,地理上的域名,指代有行政自主权的一个地方区域)。域名是一个IP地址上有“面具” 。域名的目的是便于记忆和沟通的一组服务器的地址(网站,电子邮件,FTP等)。域名作为力所能及难忘的互联网参与者的名称。域名按域名系统(DNS)的规则流程组成。在DNS中注册的任何名称都是域名。域名用于各种网络环境和应用程序特定的命名和寻址目的。通常,域名表示互联网协议(IP)资源,例如用于访问因特网的个人计算机,托管网站的服务器计算机,或网站本身或通过因特网传送的任何其他服务。世界上第一个注册的域名是在1985年1月注册的。

域名结构

.TOP–适用于所有企业和个人,英文单词,简单易记,含义“高端、顶级”,提升品牌价值,是企业建站、互联网应用首选域名。
.COM–用于商业机构。它是最常见的顶级域名。任何人都可以注册.COM 形式的域名。
.XYZ–作为字母表最后三个字母,组合含义灵活,没有限制,任何企业和个人都可以注册.XYZ结尾的域名。
.NET–最初是用于网络组织,例如因特网服务商和维修商。任何人都可以注册以.NET结尾的域名。
.ORG–是为各种组织包括非盈利组织而定的,任何人都可以注册以.ORG 结尾的域名。
我国顶级域名为.cn

关于树的遍历

树的遍历顺序大体分为三种:前序遍历(先根遍历、先序遍历),中序遍历(中根遍历),后序遍历(后根遍历)。

如图所示二叉树:

NOIP初赛知识点-LMLPHP

前序遍历:前序遍历可以记为根左右,若二叉树为空,则结束返回。

前序遍历的规则:

(1)访问根节点

(2)前序遍历左子树

(3)前序遍历右子树

这里需要注意:在完成第2,3步的时候,也是要按照前序遍历二叉树的规则完成。

前序遍历的输出结果:ABDECF

中序遍历:中序遍历可以记为左根右,也就是说在二叉树的遍历过程中,首先要遍历二叉树的左子树,接着遍历根节点,最后遍历右子树。

同样,在二叉树为空的时候,结束返回。

中序遍历的规则:

(1)中序遍历左子树

(2)访问根节点

(3)中序遍历右子树

注意:在完成第1,3步的时候,要按照中序遍历的规则来完成。

中序遍历的输出结果:DBEAFC

后序遍历:后序遍历可以记为左右根,也就是说在二叉树的遍历过程中,首先按照后序遍历的规则遍历左子树,接着按照后序遍历的规则遍历右子树,最后访问根节点。

在二叉树为空的时候,结束返回。

后序遍历二叉树的规则:

(1)后序遍历左子树

(2)后序遍历右子树

(3)访问根节点

注意:在完成1,2步的时候,依然要按照后序遍历的规则来完成。

后序遍历的输出顺序:DEBFCA

关于原码,反码,补码

数值在计算机中是以补码的方式存储的,在探求为何计算机要使用补码之前, 让我们先了解原码, 反码和补码的概念。

  对于一个数, 计算机要使用一定的编码方式进行存储。 原码, 反码, 补码是计算机存储一个具体数字的编码方式。

  一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。比如,十进制中的数 +2 ,计算机字长为8位,转换成二进制就是[00000010]。如果是 -2 ,就是 [10000010] 。因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 [10000010],其最高位1代表负,其真正数值是 -2 而不是形式值130([10000010]转换成十进制等于130)。所以将带符号位的机器数对应的真正数值称为机器数的真值。

  • 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。
  • 反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
  • 补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)

举例:

那么计算机为什么要使用补码呢?

  首先,根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1+(-1), 所以计算机被设计成只有加法而没有减法, 而让计算机辨别”符号位”会让计算机的基础电路设计变得十分复杂,于是就让符号位也参与运算,从而产生了反码。
  用反码计算, 出现了”0”这个特殊的数值, 0带符号是没有任何意义的。 而且会有[0000 0000]和[1000 0000]两个编码表示0。于是设计了补码, 负数的补码就是反码+1,正数的补码就是正数本身,从而解决了0的符号以及两个编码的问题: 用[0000 0000]表示0,用[1000 0000]表示-128。
   注意-128实际上是使用以前的-0的补码来表示的, 所以-128并没有原码和反码。使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数。 这就是为什么8位二进制, 使用补码表示的范围为[-128, 127]。

关于进制转换

进制转换是个老问题了,今天恰巧看见。我详细的去分析下它。留一笔吧

    二进制的范围是(0-1), 不包含2

    八进制的范围是(0-7) ,不包含8

    十六进制的范围是(0-15) ,不包含16

    先讲十进制---->二进制的转换,举例子说明的十进制数字12

   这里我把十进制的12转换成二进制,该为多少?

   十进制转换二进制方法:十进制通通除以2

    拿12来开刀

   NOIP初赛知识点-LMLPHP

    我们每次都除以2直到商为0停止,最后的二进制结果取每次得到的余数

               最后得到结果是1100

    NOIP初赛知识点-LMLPHP

    十进制转换二进制很简单,下面逆向分析,二进制如何转换十进制

    随机一个二进制0100,我开始尝试把0100转换成十进制

    也很简单

    先看一张图

    NOIP初赛知识点-LMLPHP

    

         搞清楚上面那张图,下面运算就很简单了

          NOIP初赛知识点-LMLPHP

      十进制转换成二进制和二进制转成十进制的算法都讲完了。这只是开胃菜。我们继续:

     下面是十进制转换成八进制的演示:

     学到这里相信大家都已经知道十进制转换成二进制是:十进制数字每次都除以2

     那么十进制转换成八进制是否有这种类似的规律可言呢?  

     猜的没错,的确如此。十进制转换成八进制就是:十进制数字每次都除以8

     我们奖十进制54转换成八进制

     NOIP初赛知识点-LMLPHP

    这里我算出来是66

    验证下答案:

    NOIP初赛知识点-LMLPHP

  结果就是余数从下往上数,这个我在前面就讲过。

  现在开始演示八进制转换成十进制

  在上面的知识学习中我们发现二进制转换成十进制是:二进制数字*2^n次方(n随位置的变化而变化)

   那么八进制转换成十进制是否也存在这种规律呢?

  答案是必然的

      举例子说明的八进制数字是64,把64转换成十进制是多少呢?  

  NOIP初赛知识点-LMLPHP

   这里我算出来是52

   验证下结果:

 NOIP初赛知识点-LMLPHP

 没问题

  刚刚我讲解了十进制转换成八进制,同时也讲解了八进制转换十进制的方法

  现在我们需要加大难度,我们尝试将二进制转换成八进制

  该怎么做?这里存在一个算法公式:二进制每三个位置等于一个八进制数

     理解这个公式就很轻松的做这种转换

     我们随机输入二进制数字进行测试:0100101010101

 就选择我红色标记的二进制数,将它转换成八进制

  NOIP初赛知识点-LMLPHP

所以二进制0100101010101的八进制数是4525

    演示完二进制转换成八进制,那么八进制转换成二进制呢?

    一个道理,只要记住:每三个二进制=一个八进制数

    假设八进制数字是15,把15转换成二进制,我来演示下:

    NOIP初赛知识点-LMLPHP

验证结果:

     NOIP初赛知识点-LMLPHP

  #八进制转换成二进制还可以这样:先八进制转换成十进制然后在十进制转换成二进制,但是那样太麻烦,这样一次性算好比较好。

  假如你能从最前面看到这里,那我表示佩服。哈哈 

  回顾上面讲的,我们已经讲完了:十进制和二进制之间的转换和十进制,八进制,二进制之间的转换

  写到这里,笔者自己也有点乱了,不要说了,一鼓作气!下面要介绍是十六进制!

 首先讲解十进制转换成十六进制

   在进行转换之前学了解一个十六进制的基础知识:

  NOIP初赛知识点-LMLPHP

  从16进制开始,不是简单的都是数字了开始多了字母!

   好了咱们继续,这里我选取的十进制数字是:15

   我开始将十进制15转换成十六进制,会是多少呢?

  NOIP初赛知识点-LMLPHP

 现在我们尝试把十六进制转换成十进制该怎么转换?

  和之前二进制转换十进制和八进制转换成十进制一个道理,这里是:十六进制数字*16^n次方(n随位置的变化而变化)

      这里演示的十六进制数字是:23

     这里我将十六进制的23转换成十进制:

  NOIP初赛知识点-LMLPHP

 演示完了十进制和十六进制之间的转换,现在开始演示十六进制转换成八进制

  选取16进制23

  转换思路有点多。。。我随机选取一种吧,将23先转换成十进制,上面我已经做过了是35

  将十进制35转换成八进制就是:

  NOIP初赛知识点-LMLPHP

这个其实不难,就是两次转换而已

   现在演示最关键的就是二进制和十六进制之间的转换

 在讲解之前先讲解一个很重要的公式:每四个二进制=一个八进制数 (正所谓2^4=16)

    那么随机选择一个二进制数字:0100100011

  NOIP初赛知识点-LMLPHP

      二进制转换成十六进制讲完,下面是十六进制转换成二进制

      随机选取十六进制:15

    NOIP初赛知识点-LMLPHP

关于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问题还有许多有趣的东西,有待大家自己进一步的挖掘。攀登这个信息学的巅峰是我们这一代的终极目标。现在我们需要做的,至少是不要把概念弄混淆了。

整合自http://www.matrix67.com/blog/archives/105,https://blog.csdn.net/qq_34940287/article/details/78191782等dalao博客。

10-10 16:07