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

本文介绍了一个典型的问题——最大装载问题,并通过回溯法进行求解。使用了C++模板类来实现算法,针对不同类型的装载物重量进行处理。文中详细解释了递归过程,并给出了一段具体的示例代码。

//#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

### 使用回溯法解决最优装载问题的C++代码实现 以下是一个完整的C++代码示例,展示了如何利用回溯法求解最优装载问题。该问题的目标是在给定容量的容器中选择若干物品,使其总重量最大且不超过容器的容量。 #### 代码实现 ```cpp #include <iostream> using namespace std; #define MAX_N 100 // 定义最多可处理的物品数量 int n, c; // 物品总数和容器容量 int w[MAX_N]; // 存储每个物品的重量 int bestx[MAX_N]; // 记录最优解 int x[MAX_N]; // 当前解向量 int r = 0; // 剩余物品的总重量 int cw = 0; // 当前已选物品的总重量 int bestw = 0; // 当前最优解对应的总重量 void backtrack(int i) { if (i > n) { // 达到叶子节点 for (int j = 1; j <= n; j++) { bestx[j] = x[j]; } bestw = cw; return; } r -= w[i]; // 更新剩余物品的总重量 if (cw + w[i] <= c) { // 如果当前物品可以放入容器 cw += w[i]; // 加入当前物品 x[i] = 1; // 设置状态为选取 backtrack(i + 1); // 进入下一层递归 cw -= w[i]; // 回退操作 } if (r + cw >= bestw) { // 如果剪枝条件不满足,则进入右子树 x[i] = 0; // 不选取当前物品 backtrack(i + 1); // 进入下一层递归 } r += w[i]; // 恢复剩余物品的总重量 } int main() { cout << "Enter the number of items and container capacity: "; cin >> n >> c; cout << "Enter the weights of each item:" << endl; for (int i = 1; i <= n; i++) { cin >> w[i]; r += w[i]; // 累计所有物品的总重量 } backtrack(1); // 开始回溯搜索 cout << "Maximum loadable weight: " << bestw << endl; cout << "Selected items: "; for (int i = 1; i <= n; i++) { if (bestx[i]) { cout << i << " "; // 输出被选中的物品编号 } } cout << endl; return 0; } ``` --- ### 代码解析 1. **全局变量定义** - `n`: 表示物品的数量。 - `c`: 表示容器的最大承载能力。 - `w[]`: 存储每件物品的重量。 - `bestx[]`: 保存最终的最优解(哪些物品被选中)。 - `x[]`: 保存当前正在探索的状态(是否选择了某个物品)。 - `r`: 剩余未考虑物品的总重量。 - `cw`: 当前已选物品的总重量。 - `bestw`: 当前找到的最佳解的总重量[^1]。 2. **`backtrack` 函数** - 参数 `i` 表示当前正在决策第几个物品。 - 首先判断是否到达叶节点(即已经处理完所有的物品),如果是,则更新最佳解。 - 接着尝试将当前物品加入集合(如果不会超过容器容量),并递归处理下一物品。 - 然后尝试跳过当前物品,并递归处理下一物品。 - 利用约束条件 `if (r + cw >= bestw)` 实现剪枝操作,减少不必要的搜索路径[^2]。 3. **主函数 (`main`)** - 输入物品数量、容器容量以及各物品的重量。 - 调用 `backtrack` 函数开始搜索。 - 最终输出能够达到的最大载重量及所选物品列表[^3]。 --- ### 示例运行 #### 输入: ``` Enter the number of items and container capacity: 5 10 Enter the weights of each item: 7 2 6 5 4 ``` #### 输出: ``` Maximum loadable weight: 10 Selected items: 2 3 ``` 解释:选择第二件物品(重量为2)和第三件物品(重量为6),总重量恰好等于容器容量10。 --- ### 时间复杂度分析 最坏情况下,算法的时间复杂度为 \(O(2^n)\),因为可能需要枚举所有可能的组合。然而,通过引入剪枝策略,实际运行时间通常会显著缩短[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值