完全背包

女生的网名这么多〃 提交于 2020-02-01 22:40:30

问题描述:

 

 

基本思路:

这个问题和 01背包 问题非常的相似,只是 01背包 问题要求了每个物品我们最多可以选一次(选和不选两种选择),但是完全背包问题只要容量够我们可以无限制的选

如果我们依然采取和 01背包 一样的状态的定义

dp[i][j] 代表 前 i 个物品 容量为 j 的时候的最大价值

那么状态转移方程也就出来了:

dp[i][j]   =    max(dp[i][j],dp[i][j-k*v[i]]+w[i]);

 

int dp[1010][1010];
int v[1010],w[1010];

int main() {
    int n,m;
    std::cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        std::cin >> v[i] >> w[i];
    }
    for (int i = 1;i <= n;i++) {
        for (int j = 0;j <= m;j++) {for (int k = 0;k * v[i] <= j;k++) {
                dp[i][j] = std::max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);
            }
        }
    }
    std::cout << dp[n][m] << std::endl;
    return 0;
}

 

但是稍微分析一下这个算法的时间复杂度 和 空间复杂度都是比较高的

 

我们可以采取和之前 01背包 一样的优化方法去优化一下

简单的优化:

之前讲 01背包 采取滚动数组的方法去优化必须要从大往小更新,这是因为我们每次都是要之前的状态

但是 完全背包 的话我们可以看作他是在 01背包的基础上取了之后再继续取,所以我们每次都是在更新之后的状态上进行更新,也就是我们要从小往大更新

 

这样这个算法的复杂度就变成了 O(N * M)

 

int dp[1010];

int main() {
    int n,m;
    std::cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        int v,w;
        std::cin >> v >> w;
        for (int j = v;j <= m;j++)
            dp[j] = std::max(dp[j],dp[j-v]+w);
    }
    std::cout << dp[m] << std::endl;
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!