/*
01 背包问题:选与不选的问题
一个容量为10的背包,共有4件商品,他们的价值和重量分别为
价值 重量
v w
2 2
4 3
3 5
7 5
将他们装入背包中,所得到的价值最大是多少,并且求选择是哪些商品
输入第一行 背包容量Capacity和商品数量n
接下来一行输入4件商品的价值和重量
输出:装入背包中的最大价值
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include <set>
using namespace std;
#define MAXN 1002
#define MAXCAPACITY 1002
int v[MAXN]; //全局数组 自动初始化为0
int w[MAXN];
int f[MAXN][MAXCAPACITY]; //代表选择物品i,最大承重量为j的情况下的最大价值
vector<int> node;
void knapsack_01(int n, int capacity)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= capacity; j++)
{
if (w[i] > j) //背包装不下
{
f[i][j] = f[i - 1][j];
}
else
{
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]); //max{选择该物品,不选择该物品}
}
}
}
printf("max value:%d\n",f[n][capacity]);
//找放入背包的物品编号
//从价值最大的物品开始遍历
int i = n;
int j = capacity;
for (; i > 0; i--)
{
for (; j > 0; j--)
{
if (f[i - 1][j] == f[i][j])
{
i = i - 1;
j = j + 1;
continue;
}
else if (f[i][j - 1] == f[i][j])
{
continue;
}
else
{
node.push_back(i);
j = j - w[i];
break;
}
}
}
printf("选择的物品编号:");
for (int i = node.size() - 1; i >= 0; i--)
{
printf("%d ", node[i]);
}
printf("\n");
}
int main()
{
int c, n;
scanf("%d %d", &c, &n);
for (int i = 1; i <= n; i++) //从下标为1开始输入!!
{
scanf("%d %d", &v[i], &w[i]);
}
knapsack_01(n, c);
return 0;
}
二维数组的填充如下:
根据结果,我们可以反向找出各个物品的选择,就是从i = 4, j = 10 开始寻找,如果f[i-1][j]=f[i][j],说明第i个物品没有被选中,从f[i-1][j]开始找。否则,从f[i-1][j-w[i]]开始寻找。粉红色的线为寻找的路线
for (; i > 0; i--)
{
for (; j > 0; j--)
{
if (f[i - 1][j] == f[i][j]) //第i个物品没有被选中
{
i = i - 1;
j = j + 1;
continue;
}
else if (f[i][j - 1] == f[i][j]) //第i个物品被选中,但有多余容量,如下图的情况
{
continue;
}
else //第i个物品被选中
{
node.push_back(i);
j = j - w[i]; //从f[i-1][j-w[i]]开始寻找
break;
}
}
}
参考文章:https://www.cnblogs.com/mfrank/p/10533701.html
三种背包的优化:
https://blog.csdn.net/qq_45282116/article/details/107349050