01背包 分支限界法

01背包 分支限界法

伪代码:
输入:n个物品的重量w[n],价值v[n],背包容量W
输出:背包获得的最大价值和装入背包的物品
1.根据限界函数计算目标函数的上界upbound,采用贪心法得到下界downbound;
2.计算根节点的目标函数值并加入待处理结点表PT;
3.循环直到某个叶子结点的目标函数值在PT中取得极大值
3.1 nodei=表PT中具有最大值的结点
3.2 对结点nodei的每个孩子结点x执行下列操作:
3.2.1 如果结点x不满足约束条件,则丢弃该结点;
3.2.2 否则,估算结点x的目标函数值,结点x加入PT表;
4.将叶子结点对应的最优值输出,回溯求得最优解的各个分量。

图片(帮助理解):
01背包 分支限界法_第1张图片
代码:

#include
#include
#include
#define MAX 100
using namespace std;

double MaxValue = 0; 

struct Node{
	double w;
	double v;
	int level;
	double ub;
	int flag;
	struct Node *parent;
};

Node *PT[MAX];

int empty(Node *PT[],int count){
	for(int a=0;a<=count;a++){
		if(PT[a]->flag==0)
			return 0;
	}
	return 1;
}

int IsMax(Node *PT[],int count,Node *x){
	for(int a=0;a<=count;a++){
		if(x->ub<PT[a]->ub && PT[a]==0)
			return 0;
	}
	return 1;
}

Node *maxofPT(Node *PT[],int count){
	double max=0;int r=-1;
	for(int a=0;a<=count;a++){
		if(PT[a]->ub>max&&PT[a]->flag==0){
			max = PT[a]->ub;
			r = a;
		}	
	}
	PT[r]->flag=1;
	return PT[r];
}

Node *bestleaf(Node *PT[],int count,int n){
	Node * leaf;
	double max =0;
	for(int a=0;a<=count;a++){
		if ( (PT[a]->level==n) && (PT[a]->ub>max) ){
			max = PT[a]->ub;
			leaf = PT[a];
		}
	}
	return leaf;
}

int *bag(double w[],double v[],int W,int n){
	int i;
	int count = 0;
	int weight=0,downbound=0;
	int *x;
	x = (int *)malloc(sizeof(int)*n);
	for(i=0;i<n;i++){
		x[i]=-1;
	}
	//求上界 
	double upbound = W*(v[0]/w[0]);
	//贪心法求下界
	for(i=0;i<n;i++){
		if(weight+w[i]<=W){
			weight+=w[i];
			downbound+=v[i];
		}
	}
	Node *N = (Node *)malloc(sizeof(Node)*1);

	N->flag=0;
	N->w=0;
	N->v=0;
	N->level=0;
	N->ub = upbound;
	N->parent=NULL;
	PT[count]=N;
	
	Node * leaf = (Node *)malloc(sizeof(Node)*1);
	
	Node *nodei = (Node *)malloc(sizeof(Node)*1);
	
	while( 1 ){
//		cout<<"PT-------PT:"<
//		for(int a=0;a<=count;a++){
//			if(PT[a]->flag==0)
//				cout<ub<<" ";
//		}
//		cout<
		nodei = maxofPT(PT,count);
//		cout<<"nodei->ub"<ub<
		//若不是叶子结点则处理它的两个孩子结点 
		if(nodei->level != n){
			//左节点(放入物品) 
			Node *nodej = (Node *)malloc(sizeof(Node)*1);
			nodej->flag = 0;
			nodej->w=nodei->w + w[nodei->level];
			nodej->v=nodei->v + v[nodei->level];
			nodej->level=nodei->level+1;
			if(nodej->level != n)
				nodej->ub = nodej->v + (W-nodej->w)*(v[nodej->level]/w[nodej->level]);
			else
				nodej->ub = nodej->v;
			nodej->parent=nodei;
			if(nodej->w<=W){
				PT[++count] = nodej;
//				cout<<"加入PT1"<
			}
			//右结点(不放入物品)
			Node *nodek = (Node *)malloc(sizeof(Node)*1);
			nodek->flag = 0;
			nodek->w=nodei->w;
			nodek->v=nodei->v;
			nodek->level=nodei->level+1;
			if(nodek->level != n)
				nodek->ub = nodek->v + (W-nodek->w)*(v[nodek->level]/w[nodek->level]);
			else
				nodek->ub = nodek->v;
			nodek->parent=nodei;
			if(nodek->w<=W){
				PT[++count] = nodek;
//				cout<<"加入PT2"<
			}
		}
		else{
			if(IsMax(PT,count,nodei))
				break;//循环结束 
		}
	}//while
	//将叶子结点对应的最优值输出,回溯求得最优解的各个分量
	leaf = bestleaf(PT,count,n);
//	cout<ub<<" "<w<<" "<v<
	MaxValue = leaf->v;
	while(leaf->parent!=NULL){
		if(leaf->w == leaf->parent->w)
			x[leaf->level-1]=0;
		else
			x[leaf->level-1]=1;
		
		leaf=leaf->parent;
	}
//	cout<<"count "<
	return x;//返回最优解 
}

int main(){
	double w[]={4,7,5,3};
	double v[]={40,42,25,12};
	int W = 10;
	int n = 4;
	int *r = (int *)malloc(sizeof(int)*n);
	
	//求时间花费 
	LARGE_INTEGER nFreq;
    LARGE_INTEGER nBeginTime;
    LARGE_INTEGER nEndTime;
    double time;
	QueryPerformanceFrequency(&nFreq);
	QueryPerformanceCounter(&nBeginTime);
	//计时代码区间
	 
	r = bag(w,v,W,n);//需计时语句 
	
	QueryPerformanceCounter(&nEndTime);
	time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)*1000000000/(double)(nFreq.QuadPart);
	//不计时代码区间
	
	cout<<"最大价值:"<<MaxValue<<endl; 
	cout<<"最优解:"<<endl; 
	for(int i=0;i<n;i++){
		cout<<r[i]<<endl;
	}
	cout<<time; 
	return 0;
} 

结果截图:
01背包 分支限界法_第2张图片
注释:2500是代码运行的时间(非精确),单位是纳秒。
代码没有用到queue(因为我不会)
01背包 分支限界法_第3张图片

你可能感兴趣的:(C++算法实验)