回溯法--无优化 最优装载问题

//#include "stdafx.h"

// 回溯法,解空间分为排列数和子集树,前者是不同节点顺序的排列,后者是一个(0,1,...)的向量子集
// 最大装载问题,是一个NP问题,目前只计算第一艘船,属于子集树
// 有几个货物,子集树就有几层,当前题目为5层
// 我感觉递归还是太过于精巧和经凑,很难挖空心思自己写出来,多熟悉别人现有的程序是一个好办法。

#include<iostream>
using namespace std;

template<class T>
class Loading {
friend T GetMaxLoading(T [], T, int);
public:
void Compute(int i);
int n; // 货箱数量
T *w, // 货箱重量数组
c, // 第一艘船的容量
cw, // 当前的装载重量
bestw; // 目前最优装载重量
};

// 重要特性:在遍历的时候,就得到了结果。使用全局变量保存了最大装载值
// 此函数一共只有一处return
// 运算过程:
// 第一、第二层能放下货物,走的是if语句的条件分支,然后开始计算第三层。
// 第三层因为不满足if语句条件,直接走的是if语句后面的语句,什么值都不改变。
// 第四、第五层直接走的是if语句后面的语句,什么值都不改变。
// 第六层返回,于是第五、第四、第三都直接返回,相当于第二层的Compute(i+1);语句计算完毕(但第二层整个过程没有计算完毕,后面还有其它语句)
// 此时,相当于第二层x=1的情况的子树计算完毕了,但还要在这层继续计算x=0的子树。
// 所以把当前cw值恢复成不装当前货物时候的值,即程序继续往下执行cw -= w[i];语句
// 然后相当于,在第二层不装货物的情况下,开始遍历计算第三层的值。等它返回之后,根节点的左子树计算完毕。
template<class T>
void Loading<T>::Compute(int i)
{
cout << " i= " << i << ", ";
cout << " cw= " << cw << endl;
// if (i==n) cout << endl;

if (i > n) { // 在叶节点
if (cw > bestw) bestw = cw; // 到了叶节点就要判断,是否得到了比当前最大装载更大的值
cout << " 终点了!返回!" << endl;
return;
}
// 能放下当前货箱的重量,继续深度遍历,当前最大装载cw加上当前货箱的重量
if (cw + w[i] <= c) { // 尝试 x[i]=1,能装下当前货箱的重量
cout << " 放下当前货箱的重量=" << w[i] << ",准备深度遍历" << i+1 << "层" << endl;
cw += w[i];
Compute(i+1); // 放下了当前货物之后,就立刻尝试下一层,直到超出为止。即所谓深度遍历算法
// 而且瞎试,反正超过了叶节点后会自动返回。
cw -= w[i]; // 下一层返回了,必然是到了最底层(不确定)
}
// 放不下当前货箱,但继续深度遍历,当前最大装载cw不变
// 放不下的时候,直接就返回了,没有在Compute(i+1); 的下面再放其它语句
// 放不下当前货箱的时候,什么都不干、什么都不改变,它自身就等着返回了。
// ,只继续深度遍历期待它的子树能放下一部分东西的时候改变一些东西。
cout << " 放不下,准备深度遍历" << i+1 << "层" << endl;
Compute(i+1); // 尝试 x[i]=0,放不下当前货箱的重量。
}

template<class T>
T GetMaxLoading(T w[], T c, int n)
{
Loading<T> X;
X.w = w;
X.c = c;
X.n = n;
X.bestw = 0;
X.cw = 0;

// 计算最佳装载,从1层算起(很重要)。0层是无用值,放弃。
X.Compute(1);
// 因为是自动递归计算,所以返回的时候,已经得到了最大装载值
// 返回的是全局变量的最大装载值,不是Compute函数的返回值
return X.bestw;
}

int main(void)
{
int w[6] = {0, 7, 2, 6, 5, 4}; // 5个货物,w[0]放弃
int n = 5;
int c = 10;
cout << "Value of max loading is" << endl;
cout << GetMaxLoading(w,c,n) << endl;
}

转载于:https://www.cnblogs.com/ITXIAZAI/p/4146155.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值