从上个星期就一直卡着的用队列式分支界限法解装载问题终于在今天告破,心里那个激动啊,想想为什么一个星期都没有找出错误呢,是因为我自己只看代码而不去进一步推敲他,今天自己在草稿纸上推导了一遍,一下子就发现错误了,那么为什么我以前不推导呢,太懒了呗。呵呵。言归正传吧,下面贴出我的代码,供自己以后参考使用。#include<iostream> #include <queue> using namespace std; typedef struct QNode { QNode * parent;//该结点的父节点 int LChild;//左子树标志位 int weight;//货物重量 }QNode; void EnQueue(queue<QNode *>&q,int wt,int i,int n,int bestw,QNode *E,QNode *&bestE,int bestx[],int ch) { if(i==n)/*到达叶子结点时就没有子结点了,只做以下操作。*/ { if(wt==bestw)//用于定位最优解,如果 { bestE=E; bestx[n]=ch; // return; } int j; for(j=n-1;j>0;j–) { bestx[j]=bestE->LChild; bestE=bestE->parent; } /*这里是输出所有最优解。如果想只输出一个最优解的话可以通过一个flag变量控制。*/ for(j=1;j<=n;j++) cout<<bestx[j]<<” “; cout<<endl; return;//这样队列中不会插入叶子节点,但是已经通过bestx[]记录了叶子节点。 } QNode *b; b=new QNode;// b->weight=wt; b->parent=E; b->LChild=ch; q.push(b); } int MaxLoading(int w[],int c,int n,int bestx[]) { queue<QNode *> q; q.push(0); int i=1,j; /*Ew表示当前重量,bestw表示最优重量,r表示剩余货物重量*/ int Ew=0,bestw=0,r=0; for(j=2;j<=n;j++) r+=w[j]; QNode *E=0,*bestE; while(1) { //test lchild int wt=Ew+w[i]; if(wt<=c)//x[i]=1 { if(wt>bestw) bestw=wt; EnQueue(q,wt,i,n,bestw,E,bestE,bestx,1); } /*这里是剪去部分右支,不是完全剪去,这是为了保存最有路径,因为没有完全剪枝,所有最优解存在多解*/ if(Ew+r>=bestw) /*test rchild,if(Ew+r>bestw)这样不行。*/ EnQueue(q,Ew,i,n,bestw,E,bestE,bestx,0);//x[i]=0 E=q.front();//取出队列头元素 q.pop();//队列删除头元素 if(!E)/*队列中是用0元素来分层的,因此如果取出的投缘素是0的话表示一层的结束*/ { if(q.empty())/*如果队列已空,则结束*/ break; q.push(0); E=q.front(); q.pop(); i++; r-=w[i]; } Ew=E->weight; } /* for(j=n-1;j>0;j–) { bestx[j]=bestE->LChild; bestE=bestE->parent; } */ return bestw; } int main() { int n=3; int c=60;/*设置检测值分别为50 70 80 90 100*/ int w[]={0,10,40,40}; int bestx[100]; cout<<MaxLoading(w,c,n,bestx)<<endl; return 0; }
2009/12/4修改如下
今天和老师讨论的时候发现前面的代码有错误,是在最优解结构那边错了,前面我举的例子是[10,40,40],这样的例子太特殊,所以没有发现问题。在确定最优解的时候,前面得到的bestw不能保证就是最有的,因为后面可能还有更优的,因此必须得遍历全部以后得到的bestw才是要求的bestw,因此我们不能再前面就输出最优解。如果只有一个最优解结构的话,那么久输出那么一个,但是如果存在多个最优解结构的话,那么输出的是最有找到的那个最优解结构。这里我还没有解决如何输出最前面的那个最优解结构,如果有人能再我的基础上改进下的话,可以留言,大家交流下,当然可能我一开始的构思就是错误的,导致后面想改也很难,大家可以把自己的代码贴出来。
下面是我更正过的代码:
#include<iostream> #include <queue> using namespace std; typedef struct QNode { QNode * parent;//该结点的父节点 int LChild;//左子树标志位 int weight;//货物重量 }QNode; void EnQueue(queue<QNode *>&q,int wt,int i,int n,int bestw,QNode *E,QNode *&bestE,int bestx[],int ch) { if(i==n)/*到达叶子结点时就没有子结点了,只做以下操作。*/ { if(wt==bestw)//用于定位最优解,如果 { bestE=E; bestx[n]=ch; return; } } QNode *b; b=new QNode;// b->weight=wt; b->parent=E; b->LChild=ch; q.push(b); } int MaxLoading(int w[],int c,int n,int bestx[]) { queue<QNode *> q; q.push(0); int i=1,j; /*Ew表示当前重量,bestw表示最优重量,r表示剩余货物重量*/ int Ew=0,bestw=0,r=0; for(j=2;j<=n;j++) r+=w[j]; QNode *E=0,*bestE; while(1) { //test lchild int wt=Ew+w[i]; if(wt<=c)//x[i]=1 { if(wt>bestw) bestw=wt; EnQueue(q,wt,i,n,bestw,E,bestE,bestx,1); } /*这里是剪去部分右支,不是完全剪去,这是为了保存最有路径,因为没有完全剪枝,所有最优解存在多解*/ if(Ew+r>=bestw) /*test rchild,if(Ew+r>bestw)这样不行。*/ EnQueue(q,Ew,i,n,bestw,E,bestE,bestx,0);//x[i]=0 E=q.front();//取出队列头元素 q.pop();//队列删除头元素 if(!E)/*队列中是用0元素来分层的,因此如果取出的投缘素是0的话表示一层的结束*/ { if(q.empty())/*如果队列已空,则结束*/ break; q.push(0); E=q.front(); q.pop(); i++; r-=w[i]; } Ew=E->weight; } for(j=n-1;j>0;j–) { bestx[j]=bestE->LChild; bestE=bestE->parent; } return bestw; } int main() { int n=4; int c=60;/*设置检测值分别为50 70 80 90 100*/ int w[]={0,10,40,50,20}; int bestx[100]; cout<<MaxLoading(w,c,n,bestx)<<endl; int j; for(j=1;j<=n;j++) //输出最优解结构 cout<<bestx[j]<<” “; cout<<endl; return 0; }