背包问题

//------------------------------------------------------------------------

//0/1背包问题
//有N件物品和一个容重为g的背包。假设第i件物品的重量是G[i],价值是V[i]。
//求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
//解题思路
//这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
//用子问题定义状态:即bag(i,g)表示前i件物品放入一个容重为g的背包可以获得的最大价值。
//则其递归函数便是:bag(i,g)=max{bag(i-1,g),bag(i-1,g-G[i])+V[i]} 。


#ifndef max
 #define max(x,y) (x)>(y)?(x):(y)
#endif

#ifndef N
 #define N 5//物品数量
#endif
int A[N];//选取某物品时可得到的最大价值
int B[N];//不选取某物品时可得到的最大价值
int G[N]={3,1,5,2,4};//存放物品重量//
int V[N]={10,3,14,5,11};//存放物品价值//

 

//参数n=物品号,g=容重,返值为所选物品总价值
//初值n=物品最大编号,g=背包最大容重
int bag1(int n,int g)
{
 if(n<0) return 0;//终止条件
 
 if(g<G[n]) return bag1(n-1, g);//不能放了
 A[n] = bag1(n-1,g-G[n]) + V[n];//将n号物品放入
 B[n] = bag1(n-1, g);//不将n号物品放入
 return max(A[n], B[n]);//返回最大值
}


//完全背包问题
// 题目
// 有N种物品和一个容量为g的背包,每种物品都有无限数量可用。
// 第i种物品的重量是G[i],价值是V[i]。
// 求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
// 解题思路
// 这也是很基础的背包问题,特点是:每种物品都有无限多件,不仅可以选择放或不放,还可选择放多少。
// 用子问题定义状态:即bag(i,g)表示前i件物品放入一个容重为g的背包可以获得的最大价值。
// 则其递归函数便是:bag(i,g)=max{bag(i-1,g),bag(i,g-G[i])+V[i]} 。
// 两个递归函数差别在于i是否变化,此处i不变意味着下次依然可以选择第i种物品

 

//参数n=物品号,g=容重,返值为所选物品总价值
//初值n=物品最大编号,g=背包最大容重
int bag2(int n,int g)
{ if(n<0) return 0;//终止条件

 if(g<G[n]) return bag2(n-1, g);//不能放了

 A[n] = bag2(n,g-G[n]) + V[n];//将n号物品放入
 B[n] = bag2(n-1, g);//不将n号物品放入
 return max(A[n], B[n]);//返回最大值
};

 

 

//多重背包问题
// 题目
// 有N种物品和一个容量为g的背包,每种物品都有C[i]数量可用。
// 第i种物品的重量是G[i],价值是V[i]。
// 求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
// 解题思路
// 这也是很基础的背包问题,特点是:每种物品都有多件,但数量是有限的,可以选择放或不放,和放多少。
// 用子问题定义状态:即bag(i,g)表示前i件物品放入一个容重为g的背包可以获得的最大价值。
// 解题思路
// 可以化简为0/1背包问题
// 方法是:将第i种物品分成若干件物品,其中每件物品的重量和价值均是原来的重量和价值的K倍,
// K=1,2,4,...,2^(k-1),C[i]-2^k+1,且k是满足C[i]-2^k+1>0的最大整数。
// 例如,如果第i种物品的数量C[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。
// 分成的这几件物品的系数和为C[i],表明不可能取多于C[i]件的第i种物品。
// 程序略

 

 

//怎么知道选取了哪些物品,以及该物品的数量?
//根据bag1函数我们已经得到所选物品总价值Value
//于是可以在数组A[]中查找Value,
//假设A[i]>=Value而且B[i]<Value
//那么i号物品就一定在所选之列,其价值是V[i]
//Value-V[i]就是其它物品的价值总和,按以上方法
//即可查出其它物品
//对于bag2,还要确定数量,
//数量count=(A[i]-B[i])/V[i]

 

 

//打印出物品,bag1适用
void print1(int Value)
{ printf("所选物品的价值%d=",Value);
 for(int i=N-1;i>=0;--i)
 { if(A[i]>=Value && B[i]<Value)
  { printf("%d+",V[i]);//价值
   Value-=V[i];
  }
 }
 printf("/b/n");
};

//打印出物品及数量,bag2适用
void print2(int Value)
{ printf("所选物品的价值%d=",Value);
 for(int i=N-1;i>=0;--i)
 { if(A[i]>=Value && B[i]<Value)
  { int count=(A[i]-B[i])/V[i];
   printf("%d*%d+",count,V[i]);//数量*价值
   Value-=A[i]-B[i];
  }
 }
 printf("/b/n");
};

void test()
{ int n=5,g=10; 
 int r;
 
 r=bag1(n-1,g);
 print1(r);

 

 r=bag2(n-1,g);
 print2(r);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值