问题描述
设有n个物体和一个背包,物体i的重量为wi价值为pi ,背包的载荷为M, 若将物体i(1<= i <=n)装入背包,则有价值为pi . 目标是找到一个方案, 使得能放入背包的物体总价值最高.
设n=3 ,c=10, w={4, 7 ,5,3} p={40,42,25,12}
应用贪心法求得近似解为(1, 0, 0, 0),获得的价值为40,这可以作为0/1背包问题的下界。
如何求得0/1背包问题的一个合理的上界呢?考虑最好情况,背包中装入的全部是第1个物品且可以将背包装满,则可以得到一个非常简单的上界的计算方法:
**b=W×(v1/w1)=10×10=100。**于是,得到了目标函数的界[40, 100]。
1 在根结点1,没有将任何物品装入背包,因此,背包的重量和获得的价值均为0,根据限界函数计算结点1的目标函数值为10×10=100;
2 在结点2,将物品1装入背包,因此,背包的重量为4,获得的价值为40,目标函数值为40 + (10-4)×6=76,将结点2加入待处理结点表PT中;在结点3,没有将物品1装入背包,因此,背包的重量和获得的价值仍为0,目标函数值为10×6=60,将结点3加入表PT中;
3 在表PT中选取目标函数值取得极大的结点2优先进行搜索;
4 在结点4,将物品2装入背包,因此,背包的重量为11,不满足约束条件,将结点4丢弃;在结点5,没有将物品2装入背包,因此,背包的重量和获得的价值与结点2相同,目标函数值为40 + (10-4)×5=70,将结点5加入表PT中;
5 在表PT中选取目标函数值取得极大的结点5优先进行搜索;
6 在结点6,将物品3装入背包,因此,背包的重量为9,获得的价值为65,目标函数值为65 + (10-9)×4=69,将结点6加入表PT中;在结点7,没有将物品
3装入背包,因此,背包的重量和获得的价值与结点5相同,目标函数值为40 + (10-4)×4=64,将结点6加入表PT中;
7 在表PT中选取目标函数值取得极大的结点6优先进行搜索;
8 在结点8,将物品4装入背包,因此,背包的重量为12,不满足约束条件,将结点8丢弃;在结点9,没有将物品4装入背包,因此,背包的重量和获得的价值与结点6相同,目标函数值为65;
9 由于结点9是叶子结点,同时结点9的目标函数值是表PT中的极大值,所以,结点9对应的解即是问题的最优解,搜索结束。
代码实现
#include
using namespace std;
const int N=100;
const int inf=0x3f3f3f3f;
typedef long long ll;
class HeadNode{
public:
double upper,prize,weight;//upper:节点上界,节点价值,节点重量
int leve,x[N];//
};
stack<HeadNode>high;
double w[N],p[N],cw,cp,c;
int n;
int cmp(int x,int y)
{
return p[x]/w[x]>p[y]/w[y];
}
void add(double up,double cp,double cw,bool ch,int leve)//存放节点
{
HeadNode be;//生成一个空节点
be.upper=up;
be.prize=cp;
be.weight=cw;
be.leve=leve;
if(leve<=n)
{
high.push(be);
}
}
double MaxBound(int j)//更新上界
{
double left=c-cw,b=cp;//left:剩余的容量,b:此时的价值
while(j<=n&&w[j]<=left)//通过单位体积价值算出理想情况下的最优解
{
left-=w[j];
b+=p[j];
j++;
}
if(j<=n)
b+=p[j]/w[j]*left;
return b;
}
int bfs()
{
int i=1,cw=0,cp=0;//初始在第一层,当前重量为0,当前价值为0
double bestp=0,up=MaxBound(1);//bestp:最优解,up=MaxBound(1):在根节点时候的上界
while(1)//(FIFO队列式分支限界法)此处可改为 priority_queue:优先队列,每次上界最大的在上面
{
double wt=cw+w[i];//搜索左子树的可行解
if(wt<=c)//更新
{
bestp=max(bestp,cp+p[i]);//更新可行解
add(up,cp+p[i],cw+w[i],true,i+1);//将此节点放入栈中
}
up=MaxBound(i+1);//右节点不放
if(up>=bestp)//右节点可能含有最优解
{
add(up,cp,cw,false,i+1);
}
if(high.empty())return bestp;//当栈为空的时候,此时的bestp就是最优解
HeadNode node=high.top();//把栈顶的点拿出来
high.pop();
cw=node.weight;cp=node.prize;up=node.upper;
i=node.leve;
}
}
int main()
{
cin>>n>>c;//n个物品,背包容量为c
for(int i=1;i<=n;i++)
cin>>w[i];
for(int i=1;i<=n;i++)
cin>>p[i];
sort(p+1,p+1+n,cmp);
cout<<bfs()<<endl;
}
/*
4 9
3 2 5 4
66 40 95 40
161
4 5
1 2 3 4
2 4 4 5
8
3 30
16 15 15
45 25 25
50
*/
测试数据
蟹蟹你耐心的看完,比心❤