0/1 背包问题 左右函数剪枝推导过程

要求:体重量刚好等于最大重量时的价值(tw = W)

一:最基本想法,遍历整个解空间树(所有子集解的集合)

void dfs(int i, int tw,int tv,int op){

	//找到一个解 
	if(i>n){
		if(tw==W&&tv>maxv){
			maxv = tv;
			for(int j=0;j<n;j++)
			x[j]=op[j];
		} 
	}
	
	op[i]=1,dfs(i+1,tw+w[i],tv+v[i],op);
	
	op[i]=0,dfs(i+1,tw,tv,op);
} 

二:左子树(设置约束条件)

后面要选的物品 重量不超才选 tw+t [ i ] <= W

 void dfs(int i, int tw,int tv,int op){

	//找到一个解 
	if(i>n){
		if(tw==W&&tv>maxv){
			maxv = tv;
			for(int j=0;j<n;j++)
			x[j]=op[j];
		} 
	}
	
	if(tw+t[i]<=W) //删除重量超过的物品,后面的物品都不用选择了 
	op[i]=1,dfs(i+1,tw+w[i],tv+v[i],op),op[i]=0;//回溯 
	
	dfs(i+1,tw,tv,op);
} 

三:右子树(限定条件)

tw + rw -w[ i ]>= W //剩余重量若是 < 背包重量,选与不选的意义不大,重量都不会 = 背包重量

//改进(右子树限定条件)
void dfs(int i, int tw,int tv,int rw, int op){

	//找到一个解 
	if(i>n){
		if(tw==W&&tv>maxv){
			maxv = tv;
			for(int j=0;j<n;j++)
			x[j]=op[j];
		} 
	}
	
	if(tw+t[i]<=W) 
	op[i]=1, dfs(i+1,tw+w[i],tv+v[i],rw,op),op[i]=0;//回溯 
	
	//最难理解的,当不选择物品i时,rw - w[i]=w[i+1]+w[i+2]...w[n],
	//若tw + rw -w[i] < W 说明不会选择后面的所有物品
	//不会选择是指右子树的左右子树都不会在选择了。 
	if(tw+rw-w[i]>=W)
	dfs(i+1,tw,tv, rw-w[i], op);
} 

要求:物体重量和不超过最大W , 保证价值最大

左剪枝不变,始终选的重量小于W

右剪枝后面的价值大于MAXV

void dfs(int i, int tw,int tv, int op){

	//找到一个解 
	if(i>n){
			maxv = tv;
			for(int j=0;j<n;j++)
			x[j]=op[j];
		} 
	}
	
	if(tw+t[i]<=W) 
	op[i]=1, dfs(i+1,tw+w[i],tv+v[i],rw,op),op[i]=0;//回溯 
	
	 
	if(tv + rv-v[i]>maxv)
	dfs(i+1,tw,tv, op);
} 

以上内容仅供个人学习参考

猜你喜欢

转载自blog.csdn.net/Brittney27/article/details/134519645
今日推荐