装载问题(回溯法)

装载问题(回溯法)


类似01背包问题,可以用动态规划,但有时候使用回溯法会更加高效。

#include<iostream>
#include<iomanip>
#define GOODS_NUM 4
using namespace std;

/**
* 2021.12.15
* 装载问题
* 迭代回溯,省去O(n)递归栈空间
* 时间复杂度:O(2^n)
*/

/**
* @param w[] 货物的重量数组
* @param c 一艘船的最大限重量
* @param n 货物的数量
* @param bestx[] 最优载重量的解,装了第i个货物则bestx[i]=1;否则bestx[i]=0
*/
template<class Type>
Type maxLoading(Type w[], Type c, int n, int bestx[]) {//迭代回溯法
	//返回最优载重量及其相应解,初始化根节点
	int i = 1;//当前层,从1开始,而非0
	int* x = new int[n + 1];//x[1:i-1]为当前路径。不考虑下标0,所以开辟n+1个空间。
	Type bestw = 0,//最优载重量
		cw = 0,//当前载重量
		r = 0;//剩余载重量
	for (int i = 1; i <= n; i++) {
		r += w[i];//初始化剩余载重量
	}
	while (true) {//搜索子树
		while (i <= n && cw + w[i] <= c) {//进入左子树
			r -= w[i];
			cw += w[i];
			x[i] = 1;
			i++;
		}
		if (i > n) {//到达叶节点,由于有剪枝回溯,保证每次到达叶节点一定会更新最佳路径
			for (int j = 1; j <= n; j++) {
				bestx[j] = x[j];
			}
			bestw = cw;
		}
		else {//进入右子树
			r -= w[i];
			x[i] = 0;
			i++;
		}
		while (cw + r <= bestw) {//剪枝回溯,cw+r为当前重量和接下来的所有集装箱之和,即当前的最大可能
			i--;
			while (i > 0 && !x[i]) {//*****不明白这一步的意思
				r += w[i];//只要i要发生变化了,r就会一起发生变化
				i--;
			}
			if (i == 0) {
				delete[] x;
				return bestw;
			}
			//进入右子树
			x[i] = 0;
			cw -= w[i];
			i++;
		}
	}
}

int main() {
	int w[GOODS_NUM+1] = { -1,10,30,40,20 },
		c = 70,
		* bestx = NULL,
		bestw;
	bestx = new int[GOODS_NUM + 1];
	bestw = maxLoading(w, c, GOODS_NUM, bestx);
	cout << "bestw:" << bestw << endl;
	for (int i = 1; i <= GOODS_NUM; i++) {
		cout << setw(3) << w[i];
	}
	cout << endl;
	for (int i = 1; i <= GOODS_NUM; i++) {
		cout << setw(3) << bestx[i];
	}
	delete[] bestx;
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值