回溯法经典例题--求解装载问题--C语言

问题描述:

        n个集装箱要装上一艘重量为W的轮船,重量用数组w【】表示。不考虑体积限制,先要从这些集装箱中选出重量和小于等于W并且尽可能大的若干装上船。

求解:

         货物的选择会构成一颗完全二叉树,左孩子对应选择当前物品,右孩子对应不选择。父节点的值对应当前选择下总的重量,如图。(这里只画了一部分) 

        

        但如果单纯的对二叉树进行深度递归搜索,那么时间复杂度是很大的,为2^n。

        我们可以加上一些剪枝函数,来有效的缩小时间复杂度。       

        增加变量rw,来记录剩下物品的总的重量和。

        走左孩子的前提只要加上该孩子的重量之后<=W就可继续往下走,否则直接剪枝。

        走右孩子的前提是当前已有重量tw+没选物品总重量rw-想选的物品重量>maxw,就可以继续往下走,该式子的含义是即使不选该物品,剩下的物品重量仍存在超过maxw的可能,否者直接剪枝。如图。

        可以看出带上了剪枝函数后,树的深搜会去掉很多不必要的子树,大大提高算法效率。

代码:

        i当前物品编号,n物品数量,W限制重量,rw剩余物品总重,tw当前选择总重,w【】物品的重量,temp【】记录当前选择的结果。

#include<stdio.h>
#include<iostream>
using namespace std;
#define max 10
int maxw = 0;
void dfs(int i, int n,int W, int rw, int tw, int* w, int* temp) {
	if (i == n) {
		if (tw > maxw) {
			maxw = tw;
			for (int i = 0; i < n; i++)
				cout << temp[i] << " ";
		}
	}
	else {
		if (tw + w[i] <= W) {
			temp[i] = 1;
			dfs(i + 1, n, W, rw - w[i], tw + w[i], w, temp);
		}
		if (tw + rw - w[i] > maxw) {
			temp[i] = 0;
			dfs(i + 1, n, W, rw - w[i], tw, w, temp);
		}
	}
}
int main() {
	int n = 5;
	int w[] = { 5,2,6,4,3 };
	int temp[max];
	memset(temp, 0, sizeof(temp));
	dfs(0, n, 10, 20, 0, w, temp);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值