0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求而且重量和恰好为W具有最大的价值
输入格式:
第一行输入背包载重量W及背包个数n,再依次输入n行,每行为背包重量wi和价值vi。
输出格式:
第一行输出输出装入背包内的物体编号(末尾有空格),第二行输出背包内的物体总重量和总价值。
输入样例1:
5 10
2 6
2 3
6 5
5 4
4 6
输出样例1:
1 2 3
10 14
代码解析:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串处理库
#include <iostream> // 引入C++标准输入输出库
#define MAXN 20 // 定义最大物品数为20
using namespace std; // 使用标准命名空间
int n; // 定义物品数变量
int W; // 定义背包限制重量变量
int w[MAXN] = {0}; // 定义存放物品重量的数组,下标从1开始
int v[MAXN] = {0}; // 定义存放物品价值的数组,下标从1开始
int x[MAXN]; // 定义存放最终解的数组
int maxv; // 定义存放最优解的总价值变量
// 定义求解0/1背包问题的函数
void dfs(int i, int tw, int tv, int rw, int op[]) {
int j;
if (i > n) { // 如果已经遍历完所有物品
if (tw == W && tv > maxv) { // 如果当前解满足条件且总价值大于已知最优解
maxv = tv; // 更新最优解的总价值
for (j = 1; j <= n; j++) { // 复制最优解到x数组
x[j] = op[j];
}
}
} else { // 如果还有未遍历的物品
if (tw + w[i] <= W) { // 如果当前物品可以放入背包
op[i] = 1; // 选取第i个物品
dfs(i + 1, tw + w[i], tv + v[i], rw - w[i], op); // 递归调用,尝试放入下一个物品
}
op[i] = 0; // 不选取第i个物品,回溯
if (tw + rw > W) { // 如果右子树剪枝条件成立
dfs(i + 1, tw, tv, rw - w[i], op); // 递归调用,尝试不放入第i个物品
}
}
}
// 定义输出最优解的函数
void dispasolution() {
int i;
for (i = 1; i <= n; i++) {
if (x[i] == 1) {
printf("%d ", i); // 输出被选中的物品编号
}
}
printf("\n%d %d", W, maxv); // 输出背包限制重量和最优解的总价值
}
int main() {
int i;
cin >> n >> W; // 输入物体个数和背包载重量
for (int i = 1; i <= n; i++) { // 输入各物体的重量和价值
cin >> w[i] >> v[i];
}
int op[MAXN]; // 定义临时解数组
memset(op, 0, sizeof(op)); // 初始化临时解数组为0
int rw = 0; // 计算所有物品的总重量
for (int i = 1; i <= n; i++) {
rw += w[i];
}
dfs(1, 0, 0, rw, op); // 调用求解函数
dispasolution(); // 调用输出函数
return 0;
}