01背包

01背包问题

有n个重量和价值分别为w,v,的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
限制条件
●1≤n≤100●1≤Wi,V;≤100●1≤W≤10000
输入
n=4
(w,v) = {(2,3),(1, 2),(3,4), (2,2)}W=5
输出
(选择第0、1、3号物品)
这是被称为背包问题的一个著名问题。这个问题要如何求解比较好呢?不妨先用最朴素的方法,针对每个物品是否放人背包进行搜索试试看。这个想法实现后的结果请参见如下代码:

//输入
int  n,.  W;
int w[MAX_ N],V [MAX_ N] ;
//从第i个物品开始挑选总重小于j的部分

int rec(int i, int j) 
{
      int res;
      if.(i==n)
{
     res = 0;
 }
      else if(j<w[i])
 {
      res=rec(i+1,j);
      }
      else
{
      res = max(rec(i + 1, j), rec(i + 1, j w[i]) + v[i]) ;
      return res ;
}
void solve() 
{
      printf ( "%dn", rec(0, W) ) ;}

只不过,这种方法的搜索深度是n,而且每-层的搜索都需要两次分支,最坏就需要0(2")的时间,当n比较大时就没办法解了。所以要怎么办才好呢?为了优化之前的算法,我们看下针对样例输人的情形下rec递归调用的情况。
在这里插入图片描述
如图所示,rec以(3,2)为参数调用了两次。如果参数相同,返回的结果也应该相同,于是第二次调用时已经知道了结果却白白浪费了计算时间。让我们在这里把第一次 计算时的结果记录下来,省略掉第二次以后的重复计算试试看。

接下来,我们来仔细研究- -下前面的算法利用到的这个记忆化数组。记dp[i][]为 根据rec的定义,从第i个物品开始挑选总重小于j时,总价值的最大值。于是我们有如下递推式
dp[n][j]= 0
dp[i+1][j] = dp[i+1][j] ( j<w[i])
=max(dp[i + 1][j],dp[i+1][j-w[i]]+v[ij]) (其 他)
如上所示,不用写递归函数,直接利用递推式将各项的值计算出来,简单地用二重循环也可以解决这一问题。
在这里插入图片描述
在这里插入图片描述

int dp[MAX_N + 1] [MAX_W + 1]; / DP数组
void solve()
{
for  (int i = n-1;i>= O; i--)
{
for  (intj=0;j<=W;.j++)
{
if(j<w[i])
{
dp[i] [j] = dp[i + 1][j] ) ;
}
else 
{
dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);
}
}
printf( "%d(n", dp[0] [W] ) ;
}


这是逆推,也可以选择正推,复杂度一样。
在这里插入图片描述
注意记得初始化
因为全局数组的内容会被初始化为0,所以前面的源代码中并没有显式地将初项=0进行赋值,不过当一次运行要处理多组输入数据时,必须要进行初始化,这点一定要注意。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值