动态规划 | 背包问题 | Knapsack Problem | C/C++实现
问题描述
现有价值为viv_ivi、重量为wiw_iwi的N个物品以及容量为W的背包。请根据下述条件选择物品装入背包:
所选物品的总价值尽可能高
所选物品的总重量不超过W。
输入:
第1行输入2个整数N、W,用空格隔开。接下来N行输入第 i 个物品的价值viv_ivi与重量wiw_iwi,每个物品占1行,相邻数组之间用空格隔开。
输出:
输出总价值的最大值,占1行。
限制:
1 ≤ N ≤ 100
1 ≤ viv_ivi ≤ 1000
1 ≤ wiw_iwi ≤ 1000
1 ≤ W ≤ 10000
输入示例
4 5 4 2 5 2 2 1 8 3
输出示例
13
讲解
这道题就是各个物品选与不选的组合,因此被称为0-1背包问题。如果检查N个物品所有选与不选的组合,复杂度为O(2N)O(2^N)O(2N)。
如果物品的大小w以及背包大小W均为整数,则0-1背包问题可以用动态规划法以O(NW)O(NW)O(NW)的效率求出严密解
先准备下列变量:
items[N+1]:一维数组,item[i].v、item[i].w分别记录第 i 个物品的价值和重量
C[N+1][W+1]:二维数组,C[i][w]表示前 i 个物品装入容量为w的背包时总价值的最大值
i 表示将前 i 个物品纳入考量范围,我们逐渐增加各个 i 对应的背包重量w,一步步更新C[i][w]。C[i][w]的值为下述二者中较大的一个:
1.C[i-1][w-物品 i 的重量] + 物品 i 的价值
2.C[i-1][w]
其中第1个表示当前选择物品 i 的情况,第2个表示当前不选择物品 i 的情况。另外,第1个的前提是物品 i 的重量不超过w。
只要将物品的选择情况记录在数组G[i][w]中,我们便可以还原最优解的物品组合了。例,当物品 i 被选择时,我们在G[i][w]中记录DIAGONAL, 20000 未被选择则记录TOP,这样一来我们就能寻找所选物品了
用动态规划法求解背包问题的算法如下,复杂度O(nm)O(nm)O(nm)。
用动态规划法求解0-1背包问题:
knapsack() //初始化C和G for i = 1 to N for w = 1 to N if items[i].w <= w if items[i].v + C[i-1][w-items[i].w] > c[i-1][w] C[i][w] = items[i].v + C[i-1][w-items[i].w] G[i][w] = DIAGONAL //选择物品 i esle C[i][w] = C[i-1][w] G[i][w] = TOP //不选择物品 i else C[i][w] = C[i-1][w] G[i][w] = TOP //不能选择物品
AC代码如下
#include<iostream> #include<vector> #include<algorithm> #define NMAX 105 #define WMAX 10005 #define DIAGONAL 1 #define TOP 0 using namespace std; struct Item { int value, weight; }; int N, W; Item items[NMAX+1]; int C[NMAX+1][WMAX+1], G[NMAX+1][WMAX+1]; void compute(int &maxValue, vector<int> &selection) { for(int w = 0; w <= W; w++) { C[0][w] = 0; G[0][w] = DIAGONAL; } for(int i = 1; i <= N; i++) C[i][0] = 0; for(int i = 1; i <= N; i++) { for(int w = 1; w <= W; w++) { C[i][w] = C[i-1][w]; G[i][w] = TOP; if(items[i].weight > w) continue; if(items[i].value + C[i-1][w-items[i].weight] > C[i-1][w] ) { C[i][w] = items[i].value + C[i-1][w-items[i].weight]; G[i][w] = DIAGONAL; } } } maxValue = C[N][W]; selection.clear(); for(int i = N, w = W; i >= 1; i--) { if(G[i][w] == DIAGONAL) { selection.push_back(i); w -= items[i].weight; } } reverse(selection.begin(), selection.end()); } void input() { cin>>N>>W; for(int i = 1; i <= N; i++) { cin>>items[i].value>>items[i].weight; } } int main(){ int maxValue; vector<int> selection; input(); compute(maxValue, selection); cout<<maxValue<<endl; return 0; }
- 0-1背包问题动态规划代码实现(C++实现)
- 动态规划解背包问题/C++/Knapsack problem
- 动态规划之最长公共子序列问题 C++实现
- 动态规划 背包问题 C++
- C++实现算法导论十五章动态规划之钢条分割问题
- 动态规划之完全背包问题(java实现)
- 矩阵链乘法问题(给A1A2A3...An加括号,使之乘法次数最小)动态规划问题C++实现
- c++实现0-1背包问题完整源码(动态…
- 动态规划--01背包问题 C++实现
- 动态规划之0-1背包问题(C实现)
- 动态规划与钢条切割问题 C++实现
- 动态规划之背包问题01——Java实现
- 流水线调度最优问题(装配线调度问题)动态规划 O(n)时间(线性时间)C++实现
- 动态规划之背包问题——Java实现
- C++动态规划之背包问题之多重背包求方案数之 : 新年去世(趣事)之打牌 运用递归+数组输出多重背包的路径(用了哪些物品)
- 动态规划之背包问题01——Java实现
- 0-1背包问题的动态规划实现
- PHP实现动态规划背包问题
- 完全背包问题动态规划c++
- 动态规划之背包问题01--java实现