首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

0029算法笔记——n后有关问题和0-1背包有关问题

2013-04-12 
0029算法笔记——n后问题和0-1背包问题1、n后问题问题描述:在n×n的棋盘上放置彼此不受攻击的n个皇后。按照国际

0029算法笔记——n后问题和0-1背包问题

     1、n后问题

    问题描述:在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

0029算法笔记——n后有关问题和0-1背包有关问题

     问题解析:用n元数组x[1:n]表示n后问题的解。其中,x[i]表示皇后i放在棋盘的第i行的第x[i]列。由于不允许将2个皇后放在同一列上,所以解向量中的x[i]互不相同。如果将n*n的棋盘看做是二维方阵,其行号从上到下,列号从左到右依次编号为1,2,……n。设两个皇后的坐标分别为(i,j)和(k,l)。若两个皇后在同一斜线上,那么这两个皇后的坐标连成的线为1或者-1。因此有:

0029算法笔记——n后有关问题和0-1背包有关问题

     由此约束条件剪去不满足行、列和斜线约束的子树。程序的递归回溯实现如下:

//n后问题 回溯法计算 递归#include "stdafx.h"#include <iostream>#include "math.h"using namespace std; class Queen{   friend int nQueen(int);   private:      bool Place(int k);  void Backtrack(int t);      int  n,    // 皇后个数          *x;    // 当前解      long sum;  // 当前已找到的可行方案数  }; int main(){int n=4,m;cout<<n<<"皇后问题的解为:"<<endl;m=nQueen(n);    cout<<n<<"皇后问题共有";cout<<m<<"个不同的解!"<<endl;return 0;}bool Queen::Place(int k){for (int j=1;j<k;j++){if ((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k])) {return false;}}return true;} void Queen::Backtrack(int t)//t扩展的是行{if (t>n){sum++;for (int i=1;i<=n;i++){    cout<<x[i]<<" ";}cout<<endl;}else{//探索第t行的每一列是否有元素满足要求for (int i=1;i<=n;i++){x[t]=i;if (Place(t)){Backtrack(t+1);}}} }int nQueen(int n){Queen X;X.n=n;X.sum=0;int *p=new int[n+1];for(int i=0;i<=n;i++){p[i]=0;}X.x=p;X.Backtrack(1);delete []p;return X.sum;}
     数组x记录了解空间树中从根到当前扩展节点的路径,这些信息包含了回溯法在回溯是所需要的信息。利用数组x所含的信息,可将上述回溯法表示成非递归的形式。进一步省去O(n)递归栈空间。迭代实现的n后问题具体代码如下:


     

     2、0-1背包问题

     问题描述:  

     给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

     形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找一n元向量(x1,x2,…,xn,), xi∈{0,1}, ? ∑ wi xi≤c,且∑ vi xi达最大.即一个特殊的整数规划问题。

      问题解析:0-1背包问题是子集选取问题。0-1 背包问题的解空间可以用子集树表示。在搜索解空间树时,只要其左儿子节点是一个可行节点,搜索就进入左子树。当右子树中有可能含有最优解时,才进入右子树搜索。否则,将右子树剪去。设r是当前剩余物品价值总和,cp是当前价值;bestp是当前最优价值。当cp+r<=bestp时,可剪去右子树。计算右子树上界的更好的方法是将剩余物品依次按其单位价值排序,然后依次装入物品,直至装不下时,再装入物品一部分而装满背包。

     例如:对于0-1背包问题的一个实例,n=4,c=7,p=[9,10,7,4],w=[3,5,2,1]。这4个物品的单位重量价值分别为[3,2,3,5,4]。以物品单位重量价值的递减序装入物品。先装入物品4,然后装入物品3和1.装入这3个物品后,剩余的背包容量为1,只能装0.2的物品2。由此得一个解为[1,0.2,1,1],其相应价值为22。尽管这不是一个可行解,但可以证明其价值是最优值的上界。因此,对于这个实例,最优值不超过22。

     在实现时,由Bound计算当前节点处的上界。类Knap的数据成员记录解空间树中的节点信息,以减少参数传递调用所需要的栈空间。在解空间树的当前扩展节点处,仅要进入右子树时才计算上界Bound,以判断是否可将右子树剪去。进入左子树时不需要计算上界,因为上界预期父节点的上界相同。算法的具体实现如下:



热点排行