01背包问题
1.空间复杂度O(V) 时间复杂度O(V)
/*
* 01背包问题
* 件数 5 最大重量 8
* 3 5 1 2 2
* 4 5 2 1 3
* */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"
using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxv];
/*
* w[] 物品重量
* c[] 物品价值
* dp[v] 容量为v时物品最大价值
* */
int main() {
int n, V;//件数 总容量
scanf("%d%d", &n, &V);
for (int i = 1; i <= n; i++) {
//物品容量
scanf("%d", &w[i]);
}
for (int i = 1; i <= n; i++) {
//物品价值
scanf("%d", &c[i]);
}
//边界
//使用滚动数组 倒序查找
for (int v = 0; v <= V; v++)
dp[v] = 0;
//求解
for (int i = 1; i <= n; i++) {
printf("\n");
for (int v = V; v >= w[i]; v--) {
//状态转移方程
//放入或不放入第i件物品的价值
printf("剩余v: %d ", v);
printf("w[%d]: %d ", i, w[i]);
printf("dp[%d]: %d dp[%d]+c[%d]: %d ", v, dp[v], v - w[i], i, dp[v - w[i]] + c[i]);
dp[v] = max(dp[v], dp[v - w[i]] + c[i]);
printf("新dp[%d]: %d \n", v, dp[v]);
}
}
//寻找dp[] 最大值就是答案
int max = 0, loc = 0;
for (int i = 0; i <= V; i++) {
if (dp[i] > max) {
max = dp[i];
}
}
printf("max: %d\n", max);
return 0;
}
/*
5 8
3 5 1 2 2
4 5 2 1 3
*/
测试结果:
2.空间复杂度O(nV) 时间复杂度O(nV)
/*
* 01背包问题
* 件数 5 最大重量 8
* 3 5 1 2 2
* 4 5 2 1 3
* */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"
using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxn][maxv];
bool flag[maxn] = {0};
/*
* w[] 物品重量
* c[] 物品价值
* dp[i][v] 前i件产品装入容量v时最大价值
* flag[] 最优解
* */
int main() {
int n, V;//件数 总容量
scanf("%d%d", &n, &V);
for (int i = 1; i <= n; i++) {
//物品容量
scanf("%d", &w[i]);
}
for (int i = 1; i <= n; i++) {
//物品价值
scanf("%d", &c[i]);
}
//边界
for (int v = 0; v <= V; v++)
dp[0][v] = 0;
//求解
for (int i = 1; i <= n; i++) {
for (int v = w[i]; v <= V; v++) {
//状态转移方程
//放入或不放入第i件物品的价值
dp[i][v] = max(dp[i - 1][v], dp[i - 1][v - w[i]] + c[i]);
}
}
//寻找dp[] 最大值就是答案
int max = 0, loc = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= V; j++) {
if (dp[i][j] > max) {
max = dp[i][j];
loc = j;
}
}
}
int c = loc;
for (int i = 1; i < n; i++) {
if (dp[i][c] == dp[i + 1][c]) {
flag[i] = 0;
} else {
flag[i] = 1;
c = c - w[i];
}
}
flag[n] = dp[n][c] ? 1 : 0;
for (int i = 1; i <= n; i++) {
//方案
printf("%d ", flag[i]);
}
printf("\n");
printf("max: %d\n", max);
return 0;
}
/*
5 8
3 5 1 2 2
4 5 2 1 3
*/
测试结果:
完全背包问题
1.空间复杂度O(V) 时间复杂度O(V)
与01背包问题相比,状态转移方程完全相同,物品件数变成无限多,不再是放入和不放入两种状态,v的枚举变成正向枚举
/*
* 完全背包问题——每种物品件数无限
* 件数 5 最大重量 8
* 3 5 1 2 2
* 4 5 2 1 3
* */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"
using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxv];
/*
* w[] 物品重量
* c[] 物品价值
* dp[v] 容量为v时物品最大价值
* */
int main() {
int n, V;//件数 总容量
scanf("%d%d", &n, &V);
for (int i = 1; i <= n; i++) {
//物品容量
scanf("%d", &w[i]);
}
for (int i = 1; i <= n; i++) {
//物品价值
scanf("%d", &c[i]);
}
//边界
for (int v = 0; v <= V; v++)
dp[v] = 0;
//求解
//使用滚动数组 正序枚举(倒序为01问题)
for (int i = 1; i <= n; i++) {
for (int v = w[i]; v <= V; v++) {
//状态转移方程
//放入或不放入第i件物品的价值
dp[v] = max(dp[v], dp[v - w[i]] + c[i]);
}
}
//寻找dp[] 最大值就是答案
int max = 0, loc = 0;
for (int i = 0; i <= V; i++) {
if (dp[i] > max) {
max = dp[i];
}
}
printf("max: %d\n", max);
return 0;
}
/*
5 8
3 5 1 2 2
4 5 2 1 3
*/
测试结果:
2.空间复杂度O(nV) 时间复杂度O(nV)
每种物品可以放入任意件,01背包问题中,如果选择放入第i件产品,状态要转移到dp[i - 1][v - w[i]] 而完全背包问题要转移到 dp[i ][v - w[i]] + c[i]
/*
* 完全背包问题——每种物品件数无限
* 件数 5 最大重量 8
* 3 5 1 2 2
* 4 5 2 1 3
* */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"
using namespace std;
const int maxn = 100;//物品最大件数
const int maxv = 1000;//容量上限
int w[maxn], c[maxn], dp[maxn][maxv];
int flag[maxn] = {0};
/*
* w[] 物品重量
* c[] 物品价值
* dp[i][v] 前i件产品装入容量v时最大价值
* flag[] 最优解
* */
int main() {
int n, V;//件数 总容量
scanf("%d%d", &n, &V);
for (int i = 1; i <= n; i++) {
//物品容量
scanf("%d", &w[i]);
}
for (int i = 1; i <= n; i++) {
//物品价值
scanf("%d", &c[i]);
}
//边界
for (int v = 0; v <= V; v++)
dp[0][v] = 0;
//求解
for (int i = 1; i <= n; i++) {
for (int v = w[i]; v <= V; v++) {
//状态转移方程
//放入或不放入第i件物品的价值
dp[i][v] = max(dp[i - 1][v], dp[i][v - w[i]] + c[i]);
}
}
//寻找dp[] 最大值就是答案
int max = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= V; j++) {
if (dp[i][j] > max) {
max = dp[i][j];
}
}
}
printf("max: %d\n", max);
return 0;
}
/*
5 8
3 5 1 2 2
4 5 2 1 3
*/
测试结果: