背包问题

问题描述


       背包问题是一种组合优化的 NP 完全问题:有 N 个物品和容量为 W 的背包,每个物品都有自己的体积 和价值 v,求拿哪些物品可以使得背包所装下物品的总价值最大。如果限定每种物品只能选择 个或 个,则问题称为 0-1 背包问题;如果不限定每种物品的数量,则问题称为无界背包问题或完全背包问题。

输入输出样例

       输入物品的数量,背包最大容量,每件物品的重量和价值,输出背包所能装下的物品最大价值。

Input: 5

           8

           [3, 5, 2, 1, 4]

           [4, 5, 3, 2, 2]

Output: 10

      输出结果为10:当背包装物品2,3,4时价值最大为10。


动态规划:

      我们可以用动态规划来解决背包问题。动态规划解法的关键是找到正确的状态转移方程:以 0-1 背包问题为例,我们可以定义一个二维数组 dp存储最大价值,其中 dp[i][j] 表示前 件物品体积不超过 的情况下能达到的最大价值。在我们遍历到第 件物品时,在当前背包总容量为 的情况下,如果我们不将物品 放入背包,那么动态规划方程为:dp[i][j]= dp[i-1][j],即前 个物品的最大价值等于只取前 i-1 个物品时的最大价值;如果我们将物品 入背包,假设第 件物品体积为 w,价值为 v,那么我们得到动态规划方程: dp[i][j] = dp[i-1][j-w] + v。我们只需在遍历过程中对这两种情况取最大值即可。

代码:

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;

int knapsack(vector<int> weights, vector<int> values, int N, int W) {
    vector<vector<int>> dp(N + 1, vector<int>(W + 1, 0));
    for (int i = 1; i <= N; ++i) {
        int w = weights[i - 1], v = values[i - 1];
        for (int j = 1; i <= W; ++j) {
            if (j >= w) {
                //状态转移方程:dp[i][j]为不放入第i件物品和放入i件物品两种情况的价值的最大值
                //如果放入第i件物品,前i-1件物品总重不超过j-w
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w] + v);
                /*
                完全背包问题的转移状态方程
                dp[i][j] = max(dp[i - 1][j], dp[i][j - w] + v);
                */
            }
            else {
                //边界条件:在容量为j时,如果物品i的重量w大于j,则不能放入i
                dp[i - 1][j] = dp[i - 1][j];
            }
        }
    }
    return dp[N][W];
}

int main() {
    int N = 5, W = 8;
    vector<int> weights = { 3,5,2,1,4 }, values = { 4,5,3,2,2 };
    int result = knapsack(weights, values, N, W);
    cout << result;
}

 

 

 




posted @ 2021-09-06 11:00  ChangYuanD  阅读(77)  评论(0编辑  收藏  举报