第5章 回溯法,装载问题

本文介绍了一个使用回溯算法解决两船装载货物问题的C++实现案例。该算法通过递归搜索所有可能的装载方案,并利用约束条件和限界条件进行剪枝,最终找到使第一艘船装载量最大的方案,同时确保剩余货物能在第二艘船上装载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define MAX 100

int c1, c2;		//两船的载重量
int n;			//货物数量
int w[MAX];		//货物重量
int maxw;		//最大装载量
bool finished;	//已达到装载最大量时,finished为true

void Backtrack(int k, int cw, int upperBound)
{
	if (k == n)
	{
		if (cw > maxw)
		{
			if ((maxw = cw) == c1)
			{
				finished = true;
			}
		}
	}
	else
	{
		if (cw + w[k] <= c1) //约束条件:是否还能装下货物w[k]
		{
			Backtrack(k+1, cw+w[k], upperBound);
			
			if (finished)
			{
				return;
			}
		}

		if (upperBound - w[k] > maxw) //限界条件:剩余货物的最优装载是否比当前的最优装载更好
		{
			Backtrack(k+1, cw, upperBound-w[k]);
			
			if (finished)
			{
				return;
			}
		}
	}
}

int main(void)
{
	while(scanf("%d%d", &c1, &c2) != EOF) //两艘船的装载量
	{
		scanf("%d", &n); //货物数量
		
		int totalw = 0;
		int i;
		for (i = 0; i < n; i++)
		{
			scanf("%d", &w[i]); //每个货物的重量
			totalw += w[i];
		}
		maxw = 0;
		finished = false;
		Backtrack(0, 0, totalw);
		if (totalw - maxw <= c2) //船2是否能装下剩余货物
		{
			printf("ship 1:%d\tship 2:%d\t", maxw, totalw-maxw);
			puts("OK!");
		}
		else
		{
			puts("NO!");
		}
		putchar('\n');
	}
	return 0;
}

/*
5 5
5 2 2 2 2 1
5 5
5 2 2 2 2 2
50 50
3 40 10 30
50 50
3 40 10 40
49 50
3 40 10 49
50 49
3 49 40 10
36 16
8 8 2 5 6 3 6 7 11
*/

### 使用回溯法解决简单装载问题 #### 算法概述 回溯法是一种通过逐步构建候选解并验证其可行性的方法。对于装载问题,目标是将一批共 \( n \) 个集装箱分配到两艘载重分别为 \( c_1 \) 和 \( c_2 \) 的船上[^1]。每个集装箱的重量为 \( w_i \),需要判断是否存在一种合理的方式使得所有集装箱都能被成功装载。 为了实现这一目标,可以采用递归方式遍历可能的解决方案,并利用剪枝技术减少不必要的计算开销[^4]。 --- #### 解决思路 1. **定义状态变量**: 定义两个变量 `weight1` 和 `weight2` 来分别记录当前已装载到第一艘船和第二艘船上的总重量。 2. **决策过程**: 对于每一个集装箱,可以选择将其放入第一艘船或者第二艘船。每次选择后更新对应船只的剩余容量,并继续处理下一个集装箱。 3. **约束条件**: 如果某次尝试导致任意一艘船的装载量超过其最大承载能力,则该分支不可行,应回退至上一层重新选择其他可能性。 4. **终止条件**: 当所有集装箱都被考虑完毕时,检查此时两艘船的实际装载量是否满足题目要求(即不超过各自的最大承重)。 5. **优化策略**: 可以按照箱子重量降序排列后再依次尝试放置,这样有助于更早发现不合法路径从而提前结束探索;另外还可以设置全局最优解标志位,在找到符合条件的结果之后立即停止进一步搜索节省时间资源消耗[^3]。 --- #### 示例代码 以下是基于上述逻辑编写的 Python 版本程序: ```python def backtrack(index, weight1, weight2): global bestW, containers, C1, C2 # 剪枝操作:当任一船超出负荷则返回 if weight1 > C1 or weight2 > C2: return # 达成全部物品都安排完成的情况 if index >= len(containers): if (C1 - weight1) + (C2 - weight2) >= bestW: # 更新最佳结果 bestW = (C1 - weight1) + (C2 - weight2) return # 将当前容器放到第一条船上 backtrack(index + 1, weight1 + containers[index], weight2) # 或者放到第二条船上 backtrack(index + 1, weight1, weight2 + containers[index]) # 初始化参数 containers = [int(x) for x in input("请输入各集装箱重量(用逗号分隔): ").split(",")] C1, C2 = map(int, input("请输入两条船的最大载重量: ").split()) bestW = float('inf') # 初始设无穷大表示未找到任何有效方案 backtrack(0, 0, 0) if bestW != float('inf'): print(f"存在一个合理的装载方案,最小剩余空间为 {bestW}") else: print("无法找到合适的装载方案") ``` 此段脚本首先读取用户输入的数据集合以及每艘船舶所能承受的最大限度数值[C1,C2];接着调用核心函数`backtrack()`执行具体的枚举运算流程;最后依据最终得到的最佳值决定输出相应提示信息给定结论. --- #### 注意事项 - 上述例子仅展示了一种基础形式下的求解办法,实际应用当中可根据具体情况加入更多细节调整比如优先级设定或是动态规划辅助等等措施提升效率效果. - 需要注意的是由于采用了穷尽式的探寻机制所以面对规模较大的实例可能会面临性能瓶颈问题因此建议针对特定场景做适当改进优化[^2]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

庞老板

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值