1、5.2装载问题,1、问题描述有一批共n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量为wi,且,装载问题要求确定是否有一个合理的装载方案可将这n个集装箱装上这2艘轮船。如果有,找出一种装载方案。 容易证明,如果一个给定装载问题有解,则采用下面的策略可得到最优装载方案。 (1)首先将第一艘轮船尽可能装满; (2)将剩余的集装箱装上第二艘轮船。,将第一艘轮船尽可能装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近。由此可知,装载问题等价于以下特殊的0-1背包问题。,用回溯法设计解装载问题的O(2n)计算时间算法。在某些情况下该算法优于动态规划算法。,解空间:子集
2、树 可行性约束函数(选择当前元素): 上界函数(不选择当前元素):当前载重量cw+剩余集装箱的重量r当前最优载重量bestw,2算法设计,void backtrack (int i)/ 搜索第i层结点if (i n) / 到达叶结点更新最优解 bestx,bestw;return; if (cw + wi = c) / 搜索左子树/ xi = 1;cw += wi;backtrack(i + 1);cw -= wi; / xi = 0; / 搜索右子树backtrack(i + 1); ,#include “stdio.h“ template class Loadingfriend Type
3、MaxLoading(Type ,Type,int);private:void Backtrack(int i);int n; /集装箱数量Type *w,c,cw,bestw;/集装箱重量数组,第一艘轮船; /的载重量,当前载重量,当前 /最优载重量,template void Loading:Backtrack(int i) if(in) /到达叶子结点if(cwbestw) bestw=cw;return; /搜索子树if (cw+wi=c) /xi=1cw+=wi;Backtrack(i+1);cw-=wi;Backtrack(i+1); /xi=0,template Type Max
4、Loading(Type w,Type c,int n)Loading X;X.w=w; X.c=c;X.bestw=0; X.n=n;X.cw=0; X.Backtrack(1);return X.bestw;void main() float w=0,8.0,6.0,2.0,3.0,max,c=12.0;max=MaxLoading(w,c,4);printf(“max=%6.2fn“,max);,3、上界函数,算法Backtrack中引进一个上界函数,用于剪去不含最优解的子树,设Z是解空间树第i层上的当前可扩展结点。cw是当前重量;bestw是当前最优载重量,r是剩余集装箱的重量,即r=
5、 定义的上界函数为cw+r。在以Z为根的子树中任一叶子结点所相应的载重量均不超过cw+r。因此,当cw+rbestw时,可将Z的右子树剪去。,class Loadingpublic:friend Type MaxLoading(Type ,Type,int);private:void Backtrack(int i);int n; /集装箱数量Type *w,c; /集装箱重量数组,/第一艘轮船的载重量,Type cw,bestw; /当前载重量,当前最优载重量Type r /剩余集装箱的重量 ;,template void Loading:Backtrack(int i) if(in) /到
6、达叶子结点if(cwbestw) bestw=cw;return; /搜索子树r-=wi;if (cw+wibestw) Backtrack(i+1); /xi=0r+=wi;,template Type MaxLoading(Type w,Type c,int n)Loading X;X.w=w; X.c=c;X.bestw=0; X.n=n;X.cw=0;X.r=0; /初始化rfor(int i=1;i=n;i+)X.r+=wi; /计算最优载重量X.Backtrack(1);return X.bestw;,void main() float w=0,8.0,6.0,2.0,3.0,ma
7、x,c=12.0;max=MaxLoading(w,c,4);printf(“max=%6.2fn“,max); /构造最优解,class Loadingpublic:friend Type MaxLoading(Type ,Type,int);private:void Backtrack(int i);int n, /集装箱数量*x, /当前解*bestx; /最优解 Type *w, /集装箱重量数组,c; 第一艘轮船的载重量,Type cw, /当前载重量bestw; /当前最优载重量Type r /剩余集装箱的重量 ;,4、构造最优解,template void Loading:Bac
8、ktrack(int i) if(in) /到达叶子结点if(cwbestw) for(j=1;jbestw) /搜索左子树xi=0;Backtrack(i+1); r+=wi;,template Type MaxLoading(Type w,Type c,int n,int bestx)Loading X;X.x=new int n+1;X.w=w; X.c=c;X.bestw=0; X.n=n;X.bestx=bestx; X.bestw=0;X.cw=0; X.r=0; /初始化rfor(int i=1;i=n;i+)X.r+=wi; /计算最优载重量X.Backtrack(1);del
9、ete X.x;return X.bestw;,#include “stdio.h“ template Type MaxLoading(Type w,Type c,int n,int bestx)int i=1;int *x=new int n+1; Type bestw,cw,r;bestw=0;cw=0;r=0;for(int j=1;j=n;j+)r+=wj;while(true)while(i=n,5、迭代回溯,if(in) for(int j=1;j0 ,5.3 n后问题,在nn格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的
10、棋子。n后问题等价于在nn格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。,解向量:(x1, x2, , xn) 显约束:xi=1,2, ,n 隐约束:1)不同列:xixj2)不处于同一正、反对角线:|i-j|xi-xj| class Queenfriend int nQueen(int);private:bool Place(int k);void Backtrack(int t);int n, /皇后个数*x; /当前解 long sum; /当前已找到的可行方案数 ;,n后问题,bool Queen:Place(int k) for (int j=1;jn) sum
11、+; for(int j=1;j=n;j+) printf(“%3d“,xj);printf(“n“);elsefor (int i=1;i=n;i+) xt=i;if (Place(t) Backtrack(t+1);,int nQueen(int n) Queen X;X.n=n; X.sum=0;int *p=new intn+1;for(int i=0;i=n;i+)pi=0;X.x=p;X.Backtrack(1);delete p;return X.sum; void main() int nQueen(int n);printf(“Queen=%dn“,nQueen(8); ,void Queen:Backtrack(int t) x1=0;int k=1;while(k0)xk+=1;while(xk=n) ,迭代回溯,上机作业2 循环赛日程表,设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次; (2)每个选手一天只能赛一次; (3)循环赛一共进行n-1天。,按分治策略,将所有的选手分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了。,