货船装箱问题的递归和非递归实现
2009-08-22 22:26
232 查看
#include <stdio.h> #include <string.h> //箱子数目 #define BOXNUM 5 //货船容量 #define MAXLOAD 21 //箱子重量 int box[BOXNUM]= {1,12,9,4,5}; //loadflag[i]为1表示第i个箱子需要装载 int loadflag[BOXNUM]; int bestloadflag[BOXNUM]; //最优装载重量 int bestload=0; //当前装载重量 int curload=0; //初始化数据 void init_data() { bestload=0; curload=0; memset(loadflag,0,sizeof(int)*(BOXNUM)); memset(bestloadflag,0,sizeof(int)*(BOXNUM)); } //递归版本货船装箱。boxi为当前要考察的箱子。 void load_recusive(int boxi) { //如果最后一个箱子已经考察过了,尝试更新最优装载重量。 if(boxi >= BOXNUM) { if(curload>bestload) { bestload=curload; memcpy(bestloadflag,loadflag,sizeof(bestloadflag)); } return; } //尝试装载当前这个箱子,然后递归。 if((curload+box[boxi]) <= (MAXLOAD)) { loadflag[boxi]=1; curload+=box[boxi]; load_recusive(boxi+1); curload-=box[boxi]; loadflag[boxi]=0; } //跳过当前这个箱子,往下递归。 load_recusive(boxi+1); } //货船装箱迭代版本。 //先解释一下搜索解空间树中,移动到左右孩子的意思。 //在解空间树上每条边都标记上0或者1,0-跳过,1-装载。 //我们总是把左孩子标记为1,右孩子标记为0。 //移动到左孩子,就是把箱子装载进来,继续考察后面的箱子。 //移动到右孩子,就是跳过当前这个箱子,继续考察后面的箱子。 //搜索解空间树的策略是: /* 尽量往左孩子移动,直到不能移动为止。 不能移动分为两种情况: (1)移动到了叶子。 (2)当前装载量没有超过货船的容量,但是如果往左孩子移动,就超过了。 如果是第二中情况,那么要尝试移动到右孩子。 只要是移动到了叶子节点,就要回溯。 回溯的策略是: (1)如果是从左孩子回退的,那么移动到右兄弟。 (2)如果是从右孩子回退的,那么先找到最左节点的父节点,然后再移动到右孩子。 如果该算法有描述不清楚的地方,请参考下面的代码。 */ int load_iterate() { //iterative version algorithm. int boxi=0; while(1) { //尽量往左子树走 while((boxi < BOXNUM) && (curload+box[boxi]<=(MAXLOAD))) { //往左子树走,意味着把当前这个box加进来。 curload+=box[boxi]; loadflag[boxi]=1; boxi++; } //往左子树走不下去了,尝试往右子树移动。 if(boxi < BOXNUM) { //往左子树走,意味着跳过当前这个box。继续考虑下一个box. loadflag[boxi]=0; boxi++; } //返回策略。 //如果碰到叶子,就返回。 //如从左孩子返回,就要移动到右兄弟。 //如从右孩子返回,就要回溯到最左节点的父节点的右孩子。 if(boxi>=(BOXNUM)) { //更新最优装载的最大重量。 if(bestload < curload) { bestload=curload; memcpy(bestloadflag,loadflag,sizeof(bestloadflag)); } //从叶子返回 boxi--; if(loadflag[boxi]) { //如果是从左孩子返回,那么要移动到右兄弟。 curload-=box[boxi]; loadflag[boxi]=0; boxi++; } else { //如从右孩子返回,就要回溯到最左节点的右兄弟。 //找到最左节点的父节点。 while(boxi>=0 && !loadflag[boxi]) { boxi--; } if(boxi<0) { printf("/n%s,%d,%s,end/n",__FILE__,__LINE__,__FUNCTION__); return bestload; } //移动到右孩子。 curload-=box[boxi]; loadflag[boxi]=0; boxi++; } } } printf("/n%s,%d,%s,end/n",__FILE__,__LINE__,__FUNCTION__); } int main() { int i; init_data(); int result=load_iterate(); printf("/n%s,%d,%s,loadnum:%d/n",__FILE__,__LINE__,__FUNCTION__,result); for(i=0; i<BOXNUM; i++) { printf(" %d ",bestloadflag[i]); } return 0; }
无论是递归版本还是迭代版本,解空间树的节点数目都是2^n, 因此时间复杂度就是O(2^n)。
改天再补充一些图例说明。
相关文章推荐
- XSLT实现XML无极限树(精简版)[二] 解决没有递归出节点属性值总和的问题(JS实现)
- 汉诺塔问题(递归实现)
- 用递归实现买鸭子问题 C语言
- 打靶问题c++代码递归实现——程序员面试宝典
- [算法]简单的背包问题递归解法,C语言实现
- 八皇后问题递归实现
- Java实现POJ 1017:装箱问题
- PHP递归实现汉诺塔问题的方法示例
- 用递归法:设计算法求解汉诺塔问题,并编程实现。 (1) Hanoi(汉诺)塔问题分析 这是一个古典的数学问题,是一个用递归方法解题的典型例子。问题是这样的:古代有一个梵塔,塔内有3个座 A,B,C
- 复杂迷宫问题的递归实现以及最短路径
- 汉诺塔问题的递归实现
- 近似装箱问题(两种脱机算法实现)
- 实验一 分治与递归―棋盘覆盖问题 java实现
- 数据结构的应用——使用栈和递归实现Hanoi问题求解
- 汉诺塔问题的递归实现
- 递归函数的练习,汉诺塔问题的程序实现(递归)
- 递归实现随机数不重复问题
- 经典汉诺塔问题——递归实现
- 递归实现打靶问题
- 常见试题:用递归实现猴子吃桃子问题