算法实验-优先队列式分支限界法解01背包问题

实验原理

分支限界法采用的是广度优先搜索,而优先队列采用的是队列里最优的出队,这里可以使用最大堆来实现活接垫优先队列,最大堆以活节点的界值作为优先级。

实验步骤

左子树的解的上界与父节点相同,不用计算。右子树的解的界值是:将剩余物品以其单位重量价值排序,然后依次装入物品,直到装不下时,再装入物品的一部分来装满背包,即采用贪心算法算出最大值,由此得到右子树中解的上界(虽然不是一个可行解,但可以作为最优解的上界)。

关键代码

double bound(int i) {
	double cleft = c - cw;
	double b = cp;
	while (i <= n && w[i] <= cleft) {
		cleft = cleft - w[i];
		b = b + p[i];
		i++;
	}
	// 装填剩余容量装满背包
	if (i <= n)
		b = b + p[i] / w[i] * cleft;
	return b;
}
// addLiveNode将一个新的活结点插入到子集树和优先队列中
void addLiveNode(double up, double pp, double ww, int lev, BBnode* par, bool ch) {
	// 将一个新的活结点插入到子集树和最大堆中
	BBnode* b = new
	BBnode(par, ch);
	HeapNode node = HeapNode(b, up, pp, ww, lev);
	heap->put(node);
}
double MaxKnapsack(){
	// 优先队列式分支限界法,返回最大价值,bestx返回最优解
	BBnode* enode = new
	BBnode();
	int i = 1;
	double bestp = 0; // 当前最优值
	double up = bound(1); // 当前上界
	while (i != n + 1) {// 非叶子结点
	// 检查当前扩展结点的左儿子子结点
		double wt = cw + w[i];
		if (wt <= c) {
			if (cp + p[i] > bestp)
				bestp = cp + p[i];
			addLiveNode(up, cp + p[i], cw + w[i], i + 1, enode, true);
		}
		up = bound(i + 1);
		if (up >= bestp)
			addLiveNode(up, cp, cw, i + 1, enode, false);
		HeapNode node = heap->removeMax();
		enode = node.liveNode;
		cw = node.weight;
		cp = node.profit;
		up = node.upperProfit;
		i = node.level;
	}
	for (int j = n; j > 0; j--) {
		bestX[j] = (enode->leftChild) ? 1 : 0;
		enode = enode->parent;
	}
	return cp;
}
double knapsack(double* pp, double* ww, double cc, int* xx) {
	// 返回最大值,bestX返回最优解
	c = cc;
	// n = sizeof(pp) / sizeof(double);
	// 定义以单位重量价值排序的物品数组
	Element* q = new
	Element[n];
	double ws = 0.0;
	double ps = 0.0;
	for (int i = 0; i < n; i++) {
		q[i] = Element(i + 1, pp[i + 1] / ww[i + 1]);
		ps = ps + pp[i + 1];
		ws = ws + ww[i + 1];
	}
	if (ws <= c) {
		return ps;
	}
	p = new double[n + 1];
	w = new double[n + 1];
	for (int i = 0; i < n; i++){
		p[i + 1] = pp[q[i].id];
		w[i + 1] = ww[q[i].id];
	}
	cw = 0.0;
	cp = 0.0;
	bestX = new int[n + 1];
	heap = new MaxHeap(n);
	double bestp = MaxKnapsack();
	for (int j = 0; j < n; j++)
		xx[q[j].id] = bestX[j + 1];
	return bestp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值