算法分析与设计--0/1背包问题(回溯法)
问题描述:
给定n种物品和一个容量为C的背包,物品i的重量是wi,其价值为vi,0/1背包问题是如何选择装入背包的物品(物品不可分割),使得装入背包中物品的总价值最大?
#include<iostream>
using namespace std;
const int n = 3; //物品个数
const int C = 25; //背包容量
int bestP = 0; //最大价值
int w[n] = {20,15, 10}; //物品重量
int p[n] = {20,30, 25}; //物品价值
int cp = 0; //当前背包价值
int cw = 0; //当前背包重量
//w[n]存储物品的重量,p[n]存储价值
//这个方法用来排序,单位价值由大到小
void sortValue(int w[], int p[],int n)
{
int index;
int temp; //暂存变量
for(int i = 0; i < n - 1; i++)
{
index = i;
for(int j = i + 1; j < n; j++)
{
//单位重量价值的比较
if((p[j] / w[j]) > (p[index] / w[index]))
{
index = j;
}
}
if(index != i) //交换记录,同时更新w和p数组
{
//交换价值记录
temp = p[index];
p[index] = p[i];
p[i] = temp;
//交换重量记录
temp = w[index];
w[index] = w[i];
w[i] = temp;
}
}
}
int Bound(int i)
{
//计算节点所相应价值的上界
int cleft = C - cw; //剩余容量
int b = cp;
//以物品单位重量价值递减顺序装入物品
while(i < n && w[i] <= cleft)
{
cleft -= w[i];
b += p[i];
i++;
}
if(i <= n)
{
b += p[i] * cleft / w[i];
}
return b;
}
//回溯求解0/1背包,寻找可行解
void BackTrack(int i)
{
if(i > n - 1)
{
bestP = cp;
return;
}
if(cw + w[i] <= C) //当前结点加上下一个结点的重量小于或等于总的背包容量
{ //进入左子树,也就是说w[i]被装入背包
cw = cw + w[i]; //背包当前的重量
cp = cp + p[i]; //当前获得的价值
BackTrack(i + 1);
//回溯,进入右子树
cw = cw - w[i];
cp = cp - p[i];
}
if(Bound(i+1) > bestP)
{
BackTrack(i + 1);
}
}
void putPackage(int w[],int p[])
{
BackTrack(0); //从根结点开始
cout<<"背包的最大价值:"<<bestP<<endl;
}
int main()
{
for(int i = 0; i < n; i++)
{
cout<<w[i]<<" ";
}
cout<<endl;
for(int i = 0; i < n; i++)
{
cout<<p[i]<<" ";
}
cout<<endl;
putPackage(w,p);
system("pause");
return 0;
}