背包问题
问题描述
背包问题是一种组合优化的 NP 完全问题:有 N 个物品和容量为 W 的背包,每个物品都有自己的体积 w 和价值 v,求拿哪些物品可以使得背包所装下物品的总价值最大。如果限定每种物品只能选择 0 个或 1 个,则问题称为 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] 表示前 i 件物品体积不超过 j 的情况下能达到的最大价值。在我们遍历到第 i 件物品时,在当前背包总容量为 j 的情况下,如果我们不将物品 i 放入背包,那么动态规划方程为:dp[i][j]= dp[i-1][j],即前 i 个物品的最大价值等于只取前 i-1 个物品时的最大价值;如果我们将物品 i 放入背包,假设第 i 件物品体积为 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; }