01背包问题(回溯)

回溯法求解0-1背包问题
	问题描述:略
	解题分析:确定约束函数和限界函数
			*约束函数:cw(i)+w(i)<=total_weight --重量
			*限界函数:B(i) = cv(i)+r(i);		--价值

	解空间组织:树或图
	树结构:子集树、排列树
	搜索方式:深度优先

算法的核心:回溯函数&限界函数,其中约束函数没有单独写出来,在代码中有用到

//回溯函数
//每个结点的左右子树都要判断,因为装或不装两种情况都要考虑
void backtrack(int i){
	//计算最大上界
	bound(i);

	if(i>c_num){
		//到达叶子结点
		bestv = cv;
		for(int k=1; k<=c_num; k++){
			//把最优解记录下来
			best[k] = x[k];
		}
		return ;
	}

	if(cw + w[i] <= capacity){
		//搜索左子树
		cw += w[i];
		cv += v[i];
		x[i] = 1;
		//深度搜索
		backtrack(i+1);
		cw -= w[i];
		cv -= v[i];
		x[i] = 0;

	}
	if(bound(i+1) > bestv)//搜索右子树,必要时剪枝
		backtrack(i+1);

}
//计算上界函数
double bound(int i){
	//背包剩余重量
	double leftw = capacity-cw;
	//背包当前价值
	double b = cv;

	for(int k = i; k<=c_num;k++){
		//剩余物品重量、价值分别存在w2、v2数组中
		w2[k]=w[k];
		v2[k] = v[k];
	}
	//将剩余物品按单位重量价值排序
	knapsack(i);

	while(i<=c_num && w2[i]<=leftw){
		//将剩余已排好序的物品装入背包
		leftw -= w2[i];
		b += v2[i];
		i++;
	}
	if(i<= c_num)
		b += v2[i]/w2[i] * leftw;
	return b;
}

其他部分:

#include "backpack.h"
#include <iostream>
using namespace std;
//声明变量
int c_num;			//物品数量
double capacity;	//背包容量
double v[100];		//各个物品的价值
double w[100];		//各个物品的重量
double cw = 0.0;	//当前背包的重量
double cv = 0.0;	//当前背包中物品价值
double bestv = 0.0;	//当前最优价值
double perv[100];	//物品按单位重量价值排序
int x[100];			//是否装入,为0或1
int best[100];		//记录最优解,为0或1
double v2[100];		//临时存放各个物品的价值
double w2[100];		//临时存放各个物品的重量
int main(){
	init();
	backtrack(1);
	cout<<"最大价值为:"<<bestv<<endl;
	cout<<"需要装入的物品编号是:"<<endl;
	for(int i = 1; i<=c_num; i++){
		if(best[i])
			cout<<i<<" ";
	}
	cout<<endl;
	system("pause");
	return 0;
}
//第一步:初始化
void init(){
	//输入物品数量n、背包容量c
	cout<<"请输入物品数量和背包容量:";
	cin>> c_num >> capacity;
	
	for(int i = 1; i<=c_num; i++){
		//输入各个物品重量wi、价值vi
		cout<<"输入第"<<i<<"个物品重量和价值:";
		cin>> w[i]>> v[i];
		perv[i] = v[i]/w[i];
		w2[i] = v2[i] = 0;
		x[i] = 0;
		best[i] = 0;
	}
}
//第二步:排序【快速排序】
void quicksort(int p, int q, double arr[], double key){
	
	int i ,j;
	i = p;
	j = q;
	if(p>=q)
		return ;
	while(1){
		while(j >= p && arr[j]<key)
			j--;

		if(j<=i)
			break;
		swap(i,j,arr);
        swap(i,j,w2);
        swap(i,j,v2);

		while(i<=q && arr[i]>=key)
			i++;                                  
        if(j<=i) 
            break;
        swap(i,j,arr);
        swap(i,j,w2);
        swap(i,j,v2);
	}
	quicksort(p,j-1,arr,arr[p]);
    quicksort(j+1,q,arr,arr[j+1]);
}


//交换两元素 
void swap(int i,int j,double arr[]){
     double t;
     t=arr[i];
	 arr[i]=arr[j];
	 arr[j]=t;                
}


//按单位价值排序
void knapsack(int t)
{       
   quicksort(t,c_num,perv,perv[t]);    
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值