单位重量价值从大到小进行排列。
仅当要进入右子树时才计算右子树的上界Bound
,以判断是否将右子树剪。进入左子树时不需要计算上界
,因为其上界与其父节点上界相同。以结点的价值上界作为优先级(由bound函数计算出)
子树最大价值上界优先级
,从堆中选择一个节点(根节点)作为当前可扩展结点。仅当右儿子结点满足上界函数约束时,才将它加入子集树和活结点优先队列。
假设有4个物品,其重量分别为(4, 7, 5, 3),价值分别为(40, 42, 25, 12),背包容量W=10。将给定物品按单位重量价值从大到小排序,结果如下:
物品 | 重量(w) | 价值(v) | 价值/重量(v/w) |
---|---|---|---|
1 | 4 | 40 | 10 |
2 | 7 | 42 | 6 |
3 | 5 | 25 | 5 |
4 | 3 | 12 | 4 |
上界计算
先装入物品1,剩余的背包容量为6,只能装入物品2的6/7(即42*(6/7)=36
)。 即上界为40+6*6=76
已第一个up为例:40+6*(10-4)=76
打x的部分因为up值已经小于等于bestp了,所以没必要继续递归了。
template<class Typew, class Typep>
Typep Knap<Typew, Typep>::Bound(int i)
{// 计算上界
Typew cleft = c - cw; // 剩余容量
Typep b = cp;
// 以剩余物品单位重量价值递减序装入物品
while (i <= n && w[i] <= cleft) {
cleft -= w[i];
b += p[i];
i++;
}
// 装满背包
if (i <= n) b += p[i]/w[i] * cleft;
return b;
}
#include
using namespace std;
class Object
{
public:
int id;
int weight;
int price;
float d;
};
class MaxHeapQNode
{
public:
MaxHeapQNode *parent;
int lchild;
int upprofit;
int profit;
int weight;
int lev;
};
struct cmp
{
bool operator()(MaxHeapQNode *&a, MaxHeapQNode *&b) const
{
return a->upprofit < b->upprofit;
}
};
bool compare(const Object &a, const Object &b)
{
return a.d >= b.d;
}
int n;
int c;
int cw;
int cp;
int bestp;
Object obj[100];
int bestx[100];
void InPut()
{
scanf("%d %d", &n, &c);
for(int i = 1; i <= n; ++i)
{
scanf("%d %d", &obj[i].price, &obj[i].weight);
obj[i].id = i;
obj[i].d = 1.0 * obj[i].price / obj[i].weight;
}
sort(obj + 1, obj + n + 1, compare);
// for(int i = 1; i <= n; ++i)
// cout << obj[i].d << " ";
// cout << endl << "InPut Complete" << endl;
}
int Bound(int i)
{
int tmp_cleft = c - cw;
int tmp_cp = cp;
while(tmp_cleft >= obj[i].weight && i <= n)
{
tmp_cleft -= obj[i].weight;
tmp_cp += obj[i].price;
i++;
}
if(i <= n)
{
tmp_cp += tmp_cleft * obj[i].d;
}
return tmp_cp;
}
void AddAliveNode(priority_queue, cmp> &q, MaxHeapQNode *E, int up, int wt, int curp, int i, int ch)
{
MaxHeapQNode *p = new MaxHeapQNode;
p->parent = E;
p->lchild = ch;
p->weight = wt;
p->upprofit = up;
p->profit = curp;
p->lev = i + 1;
q.push(p);
// cout << "加入点的信息为 " << endl;
// cout << "p->lev = " << p->lev << " p->upprofit = " << p->upprofit << " p->weight = " << p->weight << " p->profit = " << p->profit << endl;
}
void MaxKnapsack()
{
priority_queue, cmp > q; // 大顶堆
MaxHeapQNode *E = NULL;
cw = cp = bestp = 0;
int i = 1;
int up = Bound(1); //Bound(i)函数计算的是i还未处理时候的上限值
while(i != n + 1)
{
int wt = cw + obj[i].weight;
if(wt <= c)
{
if(bestp < cp + obj[i].price)
bestp = cp + obj[i].price;
AddAliveNode(q, E, up, cw + obj[i].weight, cp + obj[i].price, i, 1);
}
up = Bound(i + 1); //注意这里 up != up - obj[i].price而且 up >= up - obj[i].price
if(up >= bestp) //注意这里必须是大于等于
{
AddAliveNode(q, E, up, cw, cp, i, 0);
}
E = q.top();
q.pop();
cw = E->weight;
cp = E->profit;
up = E->upprofit;
i = E->lev;
}
for(int j = n; j > 0; --j)
{
bestx[obj[E->lev - 1].id] = E->lchild;
E = E->parent;
}
}
void OutPut()
{
printf("最优装入量为 %d\n", bestp);
printf("装入的物品为 \n");
for(int i = 1; i <= n; ++i)
if(bestx[i] == 1)
printf("%d ", i);
}
int main()
{
InPut();
MaxKnapsack();
OutPut();
}
输入
4 10
40 4
42 7
25 5
12 3
输出
最优装入量为 65
装入的物品为
1 3