时间复杂度入门 - 什么是 P 问题

中文 | English

计算复杂度基础概念简介

在进入 NP、NP 完全性、多项式规约这些更深的主题之前,首先需要建立一套共同语言: 什么是“算法的复杂度”?什么叫“多项式时间”?为什么有些算法明明很快,却不算多项式?

先介绍三个最重要的复杂度概念:

这三者会在后面内容重复出现!

Note
后面“多项式时间”可能都会缩写成 poly-time,伪多项式时间可能会缩写成 pseudo-poly-time, 弱多项式时间可能会写成 weakly-poly-time. 这个写法不一定专业,只是为了后面简单而已。

为什么要强调 poly-time?

在理论计算机科学中,我们普遍把 poly-time 作为“有效算法”的判断标准。

因为:

  1. 多项式时间算法的增长速度(如 nnlognn2n3)都可控;

  2. 换电脑、换语言、换常数,不会影响其“级别”;

  3. 多项式时间问题 = 工程上可扩展的问题;

例如:

时间复杂度是否可行评价
O(n)linear time, 非常快
O(nlogn)sort alg.级别的, 快
O(n2)这些都是没有问题的
O(n7)仍然是poly-time, 这些都是可控的
O(2n)指数爆炸
O(n!)爆炸

因此,P 类问题(Polynomial-Time Problems) 代表“可在合理时间内解决的问题”。

P 类问题

一个算法是多项式时间的,如果运行时间满足:O(nk), 其中 k 是某个常数。那么这个算法可以解决的问题,可以被称之为一个P问题。

Important
注意,不是算法是P,而是这个问题,因为可以被poly-time的算法解决,所以这个问题属于P类问题。

经典多项式时间算法例子

  1. Dijkstra 最短路径(非负权图)

  2. 最大流(Max-Flow)问题

    • Note: CSCI570-Analysis-of-Algorithms-USC/Lecture9-Network-Flow/Note.md

    • 算法时间复杂度类型
      Ford–FulkersonO(Cm)pseudo-polynomial
      Scaled version (Capacity Scaling)O(m²logC)weakly polynomial
      Edmonds–KarpO(nm²)strongly polynomial
      Orlin + KRT (改进版)O(nm)strongly polynomial
      Modern Approximation methodsO(mlogn+m4/3)almost linear time
    • 所以 Max Flow Problem 也是典型的 P 类问题

  3. 最小生成树(MST)

这些算法构成了“可高效求解”的基石。

伪多项式时间 (Pseudo-Polynomial Time)

一句话定义:

伪多项式算法的运行时间依赖于输入数字的“数值大小 V”,而不是其“二进制位数 logV”。

听起来抽象,但例子一看就懂。

经典例子:0/1 背包动态规划

 

01 Knapsack Problem DP 时间复杂度:O(nW)

其中:

注意:

W=109 的 bit-length 只有约 30 bits。

但是算法需要跑 十亿步。

因此,不是真正意义上的 polytime。

上面的解释是我当初不理解的时候,问大模型,大模型的解释。

这样解释还是很奇怪,我个人的理解是:

比如不同路径这个题目,和背包问题都是二维数组的DP,为什么前者是 poly-time, 后者不是? \ 因为在不同路径这题中,我们的输入,是二维的!而在背包问题中,W容量只是一个数字!\ 在不同路径这个问题中,如果你想要DP数组多一行,你就要把地图扩展一行,所以输入和输出的变化是同一量级的! 在背包问题中,想要DP数组多一行,我们只需要改一个数字W,让他加1就行了,而不需要输入多加一行这么个量级。\ 所以在背包问题中,一个小小数字的+1,就会导致DP数组多加一行,这种变化其实是非常大的。

不知道这样能否让大家理解。

为什么叫“伪 (pseudo)”?

因为:

例如:

Wbit-lengthDP 时间评价
100010 bitsO(n·1000)可行
10⁹30 bitsO(n·109)不可行
2¹⁰⁰100 bitsO(n·2100)爆炸

伪多项式算法常出现于 NP-Hard 问题的 DP 解法中,如:

关于 NP难 是什么意思,我后面会继续讲解的。

弱多项式时间 (Weakly Polynomial Time)

弱多项式时间介于 “真正多项式” 与 “伪多项式”之间。

一句话定义:

弱多项式时间算法依赖于 n 与输入数字的 bit-length (logV),而不是 V 本身。

因此:

经典例子:线性规划(Linear Programming, LP)

LP 的求解算法(例如 Ellipsoid、Interior-Point)运行时间大致为:poly(n,B)

其中:

强多项式时间 (Strongly Polynomial Time)

强多项式时间算法的定义:

poly(n)且不依赖logV 或 V 本身

纯粹依赖输入结构,而不是数字大小。

经典例子

强多项式算法是最稳健的复杂度类型。

三种复杂度的终极对比(非常重要)

下表是理解复杂度结构最关键的一个表格:

类型运行时间依赖示例属于 P?
强多项式 (Strong Poly)poly(n)MST、匹配✔ 是
弱多项式 (Weak Poly)poly(n,logV)线性规划 LP✔ 是
伪多项式 (Pseudo-Poly)poly(n,V)背包 DP✘ 不是(除非数字很小)

Tip
伪多项式算法看起来“快”,但实际上对 bit-length 不能保证多项式增长,因此 NP-hard 问题不被视为已解决。