问题描述
有N件物品和一个容量为C的背包。第i件物品的价值是P[i],重量是W[i]。求解将哪些物品装入背包可使价值总和最大。所谓0-1背包,表示每一个物品不能拆解,要么装入,要么不装入。
1、W=某个值,求最大价值
public class Knap {
final int MAXN = 100;
int W = 6;
int[] w = { 0, 5, 3, 2, 1, 3 };
int[] v = { 0, 4, 4, 3, 2, 9 };
int n = w.length - 1;
int[] x = new int[MAXN];
int maxv = 0;
void disp() {
for (int i = 1; i <= n; i++) {
if (x[i] == 1)
System.out.printf(i + " ");
}
System.out.println();
System.out.println(maxv);
}
void p() {
int cv = 0;
int cw = 0;
int rw = 0;
for (int i = 0; i <= n; i++)
rw = rw + w[i];
int rv = 0;
for (int i = 0; i <= n; i++)
rv = rv + v[i];
int[] op = new int[w.length];
dfs(1, cw, cv, rw, rv, op);
disp();
}
public void dfs(int i, int cw, int cv, int rw, int rv, int[] op) {
if (i > n) {
if (cw == W && cv > maxv) {
maxv = cv;
System.arraycopy(op, 0, x, 0, n + 1);
}
return;
}
// 左剪枝
if (cw + w[i] <= W && cv + rv > maxv) {
op[i] = 1;
dfs(i + 1, cw + w[i], cv + v[i], rw - w[i], rv - v[i], op);
}
// 右剪枝
if (cw + rw -w[i]>=W && cv + rv - v[i] > maxv) {
op[i] = 0;
dfs(i + 1, cw, cv, rw - w[i], rv - v[i], op);
}
}
public static void main(String[] args) {
new Knap().p();
}
}
2、W<=某个值
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Goods {
int no;
int w;
int v;
Goods(int no, int w, int v) {
this->no = no;
this->w = w;
this->v = v;
}
bool operator<(const Goods &s) const {
return (double)v / w > (double)s.v / s.w; // 按单位价值降序
}
};
vector<Goods> g;
int W, n;
vector<int> x, bestx;
int bestv = 0;
// 计算上界函数
double bound(int cw, int cv, int i) {
int rw = W - cw;
double b = cv;
int j = i;
while (j < n && g[j].w <= rw) {
rw -= g[j].w;
b += g[j].v;
j++;
}
if (j < n)
b += (double)g[j].v / g[j].w * rw;
return b;
}
// 深度优先搜索
void dfs(int cw, int cv, int i) {
if (i == n) {
if (cv > bestv) {
bestv = cv;
bestx = x;
}
return;
}
// 左孩子:选择物品 i
if (cw + g[i].w <= W) {
x[i] = 1;
dfs(cw + g[i].w, cv + g[i].v, i + 1);
}
// 右孩子:不选择物品 i(剪枝判断)
double b = bound(cw, cv, i + 1);
if (b > bestv) {
x[i] = 0;
dfs(cw, cv, i + 1);
}
}
// 背包问题求解函数
void knap(vector<Goods> g1, int W1) {
g = g1;
W = W1;
n = g.size();
sort(g.begin(), g.end()); // 按单位价值降序排列
x = vector<int>(n, 0);
bestx = vector<int>(n, 0);
bestv = 0;
dfs(0, 0, 0);
// 输出结果
cout << "最大价值: " << bestv << endl;
cout << "最佳装填方案:" << endl;
for (int i = 0; i < n; i++) {
if (bestx[i] == 1) {
cout << "选取物品编号: " << g[i].no << endl;
}
}
}
int main() {
vector<Goods> items = {
Goods(0, 5, 4),
Goods(1, 3, 4),
Goods(2, 2, 3),
Goods(3, 1, 1)
};
int capacity = 6;
knap(items, capacity);
return 0;
}