您的位置:首页 > 其它

货船装箱问题的递归和非递归实现

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)。

改天再补充一些图例说明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: