赞
踩
单位重量价值从大到小进行排列。
仅当要进入右子树时才计算右子树的上界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 <bits/stdc++.h> 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<MaxHeapQNode *, vector<MaxHeapQNode *>, 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<MaxHeapQNode *, vector<MaxHeapQNode *>, 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。