You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无界背包问题的时间复杂度真的是O(n×W)吗?

无界背包问题的时间复杂度真的是O(n×W)吗?

本文探讨无界背包问题的时间复杂度是否真的为O(n×W)。无界背包问题定义为:给定背包承重W和n个物品,每个物品具有价值value_i和重量w_i,需计算总重量≤W时可获得的最大价值,与经典背包问题不同,此处允许重复使用同一物品。

针对该问题,有一种基于动态规划的标准解法:定义函数g:(CurrentWeight, CurrentItem)->MaxRemainingValue,通过遍历物品避免隐式图中的环,进而应用动态规划。以下是该思路的C++实现代码:

#include<iostream>
#include<vector>
#include <chrono>
#define INF (int)1e8
using namespace std;
using namespace std::chrono;

const int MAX_WEIGHT = 10000;
const int N_ITEMS = 10;

int memo[N_ITEMS][MAX_WEIGHT + 1];
vector<int> weights;
vector<int> values;

void initializeMemo(){
    for(int i = 0; i < N_ITEMS; i++)
        for(int j = 0; j < MAX_WEIGHT + 1; j++)
            memo[i][j] = -1;
}

// 返回剩余重量能获得的最大价值
int dpUnboundedKnapsack(int currentItem, int currentWeight){
    if(currentItem == N_ITEMS)
        return 0;

    int& ans = memo[currentItem][currentWeight];
    if(ans != -1)
        return ans;

    int n_taken = 0;
    while(true){

        int newWeight = currentWeight + n_taken * weights[currentItem];
        if(newWeight > MAX_WEIGHT)
            break;

        int value = n_taken * values[currentItem];
        ans = max(ans, dpUnboundedKnapsack(currentItem+1, newWeight) + value);

        n_taken++;
    }

    return ans;
}

int main(){
    initializeMemo();

    // 所有物品重量为1
    weights = vector<int>(N_ITEMS, 1);

    // 物品价值为1, 2, 3, ..., N_ITEMS
    values = vector<int>(N_ITEMS);
    for(int i = 0; i < N_ITEMS; i++)
        values[i] = i+1;

    auto start = high_resolution_clock::now();
    cout << dpUnboundedKnapsack(0, 0) << endl;    
    auto stop = high_resolution_clock::now();
    auto duration = duration_cast<microseconds>(stop - start);
    cout << duration.count() << endl;

    return 0;
}

该解法遍历一个有向无环图(DAG),所有边均为(item, weight)->(item+1, new_weight)形式,无环。算法时间复杂度为O(E),其中E为图的边数。在最坏情况(所有物品重量为1)下,每个顶点(item, weight)平均连接W/2个顶点,此时O(E)=O(W²n)。但网络上普遍称该算法时间复杂度为O(n×W),理由是每个顶点仅计算一次,这与实际运行数据不符:

MAX_WEIGHT运行时间(微秒)
1001349
100045773
100005490555
2000021249396
4000080694646

从表中可明显看出,当W较大时呈现*O(W²)*的趋势。

有人可能认为这种最坏场景无意义,可通过预处理选择同重量下价值最高的物品,此时最坏场景变为物品重量为[1,2,3,...,n],此时边数约为O(W²logn + Wn),算法时间复杂度应为O(W²logn + Wn)而非广泛认可的O(n×W)?

以下是该场景下的运行时间数据:

MAX_WEIGHT运行时间(微秒)
100964
2001340
4002541
8006878
100010407
100001202582
200005181070
4000018761689

时间复杂度趋势图

参考资料:

  • [1] GeeksforGeeks 无界背包问题(允许重复选择物品)
  • [2] 维基百科 背包问题动态规划预计算算法
  • [3] Stack Overflow 为什么背包问题是伪多项式时间复杂度?

内容的提问来源于stack exchange,提问作者F. Bruno Dias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 14:03:21