问题描述:

有 n 个集装箱要装上一艘载重量为 W 的轮船,其中集装箱 i (1<=i<=n) 的重量,为wi。子啊装在体积不受限制的情况下,将尽可能重的集装箱装上轮船,当重量相同时要求选取的集装箱个数尽可能少,编写一个实验程序采用回溯法求解。要求采用适当的剪枝条件提高效率,左孩子结点剪枝的条件是只装载满足重量要求的集装箱,右孩子结点剪枝的条件是至多要选中 3 个集装箱。

例如,n=5,W=10,w[] = {5,2,6,4,3}时,其最佳装载方案是(0,0,1,1,0),既装载第3、4个集装箱。

问题分析:

看完题目感觉可以用穷举法把所有可能性全列举出来,然后从所有结果中选取一个最优解,然后输出。

but,题目需要回溯法,那么就要考虑用回溯法的思想去解决这个问题。

回溯法:在包含问题的所有解的解空间树中,按照深度搜索优先的策略,从根节点出发搜索解空间树。

下图展示的是程序的大致执行过程。

简单的说就是一直在深度优先搜索结果,查找完当前层的时候需要恢复以前修改数据,保证接下来深度搜索基准数据没有错。

如果只是简单的回溯,其实和穷举法差不多,但是 回溯法中可以写剪枝函数,把那些不满足条件的枝叶剪掉,从而加快搜索速度。

下面我们来模拟一遍回溯的过程,假设现在w[] 这个数组中只有3个元素,分别为 5 、2、6

图中黑色直线标识深度递归到某一层进行计算,蓝色的线条表示当前层计算完毕,需要恢复数据到上一层接着进行寻找。

每个节点右两个值,第一个代表当前层装的数量,第二个代表当前层的重量.

咱们设定取左孩子表示装当前 i 集装箱,取右孩子表示不装当前 i 集装箱

#include <stdio.h>#define MAXN 20int maxw=0;  //总重量
int min=65535; //装的最少数量
int res[MAXN];  //存放最终结果
int count=0;   //测试执行次数 int getMax(int a,int b)
{//获取两个数中最大值return a>b?a:b;
}void cpsz(int a[],int b[],int n)
{//复制数组int i;for(i=0;i<n;i++){b[i]=a[i];}
}// i 表示层数
// n 表示总层数
// w[] 存放每个物品重量
// W 表示最大重量
// tw 当前层的重量
// tc 当前层的数量
// opt[] 临时存放解
void f(int i,int n,int w[],int W,int tw,int tc,int opt[])
{//主要递归主体count++;printf("层数 %d 总层数 %d 最大重量 %d 当前层重量 %d 当前层数量 %d count: %d \n",i,n,W,tw,tc,count);if(i<n){//取 i 物品 左剪枝if(tw+w[i]<=W){opt[i]=1;f(i+1,n,w,W,tw+w[i],tc+1,opt);}opt[i]=0;f(i+1,n,w,W,tw,tc,opt);}else{if(tw>=maxw){maxw=tw;if(tc<min){cpsz(opt,res,n);min=tc;}}}
}void printRes(int w[],int n){int i;printf("问题最终解为\n装箱物品: ");for(i=0;i<n;i++){if(res[i]==1)printf("%d ",w[i]);}printf("\n装箱最大的容量为:%d",maxw);printf("\n装箱数量为%d\n",min);
}int main()
{int n=5;  //n个集装箱int W=10;   //轮船最大载重量int w[] = {9,4,8,6,1};    //n个物品对应的数量int opt[MAXN];   //存放临时解f(0,n,w,W,0,0,opt);printRes(w,n);return 0;
}

从执行结果可以看出来左剪枝还是起到一定效果,高度为 5 的满二叉树应该为 31 次,但实际执行了27次.

由于题上给出来右剪枝的条件,所以可以进行右剪枝.下面就是右剪枝的代码

#include <stdio.h>#define MAXN 20int maxw=0;  //总重量
int min=65535; //装的最少数量
int res[MAXN];  //存放最终结果
int count=0;   //测试执行次数 int getMax(int a,int b)
{//获取两个数中最大值return a>b?a:b;
}void cpsz(int a[],int b[],int n)
{//复制数组int i;for(i=0;i<n;i++){b[i]=a[i];}
}// i 表示层数
// n 表示总层数
// w[] 存放每个物品重量
// W 表示最大重量
// tw 当前层的重量
// tc 当前层的数量
// opt[] 临时存放解
void f(int i,int n,int w[],int W,int tw,int tc,int opt[])
{//主要递归主体count++;printf("层数 %d 总层数 %d 最大重量 %d 当前层重量 %d 当前层数量 %d count: %d \n",i,n,W,tw,tc,count);if(i<n){//取 i 物品 左剪枝if(tw+w[i]<=W){opt[i]=1;f(i+1,n,w,W,tw+w[i],tc+1,opt);}//右剪枝if(tw>3){//不取 i 物品opt[i]=0;f(i+1,n,w,W,tw,tc,opt);}}else{if(tw>=maxw){maxw=tw;if(tc<min){cpsz(opt,res,n);min=tc;}}}
}void printRes(int w[],int n){int i;printf("问题最终解为\n装箱物品: ");for(i=0;i<n;i++){if(res[i]==1)printf("%d ",w[i]);}printf("\n装箱最大的容量为:%d",maxw);printf("\n装箱数量为%d\n",min);
}int main()
{int n=5;  //n个集装箱int W=10;   //轮船最大载重量int w[] = {9,4,8,6,1};    //n个物品对应的数量int opt[MAXN];   //存放临时解f(0,n,w,W,0,0,opt);printRes(w,n);return 0;
}

进行右剪枝之后程序只执行了 7 次就出答案了, 看来右剪枝的效果还是很明显的, 但是如果题上没有给右剪枝的条件或者要求,最好不要进行右剪枝,以免程序出错。

回溯法 | 求解装载问题相关推荐

  1. 使用回溯法求解装载问题

    回溯法解决装载问题(java实现) 问题描述:有n个集装箱要装上两艘载重量分别为C1和C2的轮船,其中集装箱i的重量为wi,且:∑ wi ≤ C1+C2. 求是否有一个合理的装载方案能将这 n 个集装 ...

  2. 回溯法求解装载问题(DFS + 剪枝策略)

    参考:https://blog.csdn.net/m0_38015368/article/details/80196634 问题描述: 有n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i ...

  3. 回溯法求解N皇后问题(Java实现)

    回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并以此慢慢地扩大问题规模,迭代地逼近最终问题的解.这种迭代类似于穷举并且是试探性的,因为当目前的可 ...

  4. 【算法分析】实验 4. 回溯法求解0-1背包等问题

    目录 实验内容 实验目的 实验结果 步骤1:描述与分析 步骤2:策略以及数据结构 步骤3 步骤4 步骤5 步骤6 实验总结 实验内容 本实验要求基于算法设计与分析的一般过程(即待求解问题的描述.算法设 ...

  5. php生成迷宫图片,PHP实现基于回溯法求解迷宫问题的方法详解

    本文实例讲述了PHP实现基于回溯法求解迷宫问题的方法.分享给大家供大家参考,具体如下: 引言 最近在leetcode上看了些算法题,有些看着很简单的很常用的东西,竟然一下子想不出来怎么求解,比如说:实 ...

  6. 回溯法求解图着色问题

    回溯法求解图着色问题 #include <iostream> #include <cstdlib> using namespace std; #define n 5 #defi ...

  7. 回溯法求解N皇后问题及其时间复杂度分析

    回溯法求解N皇后问题及其时间复杂度分析 一.回溯法简介 1. 什么是回溯法? 2. 回溯法的时间复杂度分析 蒙特卡罗方法 蒙特卡罗方法在回溯法求解时间复杂度中的应用 二.回溯法求解N皇后问题 1. 回 ...

  8. 算法设计与分析 实验三 回溯法求解地图填色问题

    回溯法求解地图填色问题 一.实验目的与要求 1.实验基本要求: 2.实验亮点: 二.实验内容与方法 三.实验步骤与过程 1.未优化的回溯: (1)算法描述: (2)编程实现 (3)运行并测试: 2.对 ...

  9. 回溯法求解0-1背包问题

    回溯法求解0-1背包问题时比较随机序列和按 v/w 降序排列的算法 问题描述: 针对0-1背包问题,尝试用回溯法. 物品总数N=10,背包容量 C=26, 物品的重量数组为w={7,3,10,12,1 ...

最新文章

  1. 一级域名和二级域名的区别是什么?作用怎样?
  2. C语言学习之输入任意年份,判断是否为闰年
  3. 对用户数据进行简单的管理用,C++实现几个字符串的字典序排序
  4. mysql gtid ha_MySQl新特性 GTID
  5. JDK 8时代的抽象类与接口
  6. python字符串转换为json_在python2.7中将原始字符串转换为JSON对象
  7. Python代码转换为exe可执行程序详解
  8. HTML5开发手机项目总结
  9. hadoop 2.6 伪分布式的安装
  10. linux7关闭开机自启,redhat7 设置开机自启
  11. 笔记:Hadoop权威指南 第9章 构建Hadoop集群
  12. 360 html页面乱码,360浏览器乱码是怎么回事
  13. 陀螺研究院 | 产业区块链发展周报(11.7—11.13)
  14. 有关计算机专业工作室的名字,盘点最好听的工作室名字大全
  15. pe安装uefi linux,华硕U盘装机维护系统v2017 WIN10PE UEFI ISO版
  16. 【多任务学习-Multitask Learning概述】
  17. 质造未来,首届腾讯WeTest技术交流开放日成功举办
  18. 微信公众号卡券php开发,微信公众号实现会员卡领取功能
  19. celery(分布式任务队列)介绍+在django中异步回调使用+定时任务的使用
  20. RT_Thread中rtconfig.h解析

热门文章

  1. 【推荐】2015年5月~2016年7月开源云计算应用程序排行榜
  2. 人工智能 ---(01.基础知识)
  3. 判断指定日期为当年第几天(Java实现)
  4. 应聘恩智浦时考察正则表达式
  5. 【powerbi】自定义排序
  6. 什么是物联网?物联网如何工作?
  7. 基于STM32的电机--直流有刷电机H桥驱动的不同模式分析
  8. 陌陌 ZAO 脸,一念成魔一念成佛
  9. E - DNA Sequence POJ - 2778
  10. 七月与安生,欠一张电影票