背包问题

物品无限的背包问题:
题意:有n个物品,每件均有无穷多个,第i个物品的体积为V[i],重量为W[i]。选一些物品装到容量为C的背包中,使得物品的总体积不大于背包的体积情况下重量最大。
分析:
这个问题和之前的硬币问题类似,增加了一个新的属性——重量,把无权图变成了有权图,很简单就把”+1“改成“+W[i]”就行了;
代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxx=10000;
const int INF=(1<<30);
int n,C,V[maxx],W[maxx],dp[maxx];
int DP(int c)
{
     int &cns=dp[c];
     if(cns!=-1)
          return cns;
     cns=-INF;
     for(int i=0;i<n;i++)
          if(c>=V[i])
               cns=max(cns,DP(c-V[i])+W[i]);
     return cns;
}
int main()
{
     cin>>n>>C;
     for(int i=0;i<n;i++)
          cin>>V[i]>>W[i];
     memset(dp,-1,sizeof(dp));
     cout<<"最大重量为:"<<DP(C)<<endl;
     return 0;
}

0-1背包问题
题意:有n个物品,第i个物品的体积为V[i],价值为W[i],容积为C的背包。求在物品总体积不超过其容量下,得到的价值最大。
分析:
这个问题用刚才的方法已经不适用了,只凭“剩余体积”这个状态,无法得之每个物品是否用过。刚才的状态很混乱,相当于是每次都对每个物品进行寻找一次。应该抓住每个物品只有一次的条件,所以dp[i][j]表示 从0到i个物品中,体积为j的背包所得到的最大价值。也就是说,对于每一个物品都进行一次询问,是否放进不同容量的背包,放进去与不放进去的进行比较。选择更大价值的一个。因而其状态转移方程就已经出来了。如下:

dp[i][j]=max(dp[i-1][j],dp[i-1][j-V[i]]+W[i]);

其具体代码如下:

/*
在状态转移方程上面出错了,之前的状态是dp[i][j]=max(dp[i-1][j],dp[i][j-V{i]]+W[i])
之所以会这么写,是因为我感觉dp[i][j]就是表示在0到i个物品中,体积为j所得到的最大价值
所以dp[i][j-V[i]]就是表示把第i个物品放入其中,但是很显然dp[i][j-V[i]]没有计算出来,这样
得到结果不对,应该是对于第i-1个物品才有意义,dp[i-1][j-V[i]]就是表示把第i个物品放
入在从0到i个物品中的值,最后才把该值赋值给dp[i][j]。所以正确的状态转移方程是:
dp[][]=max(dp[i-1][j],dp[i-1][j-V[i]]+W[i])
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxx=10000;
int n,C,V[maxx],W[maxx],dp[maxx][maxx];
int main()
{
     cin>>C>>n;
     for(int i=1;i<=n;i++)
          cin>>V[i]>>W[i];
     memset(dp,0,sizeof(dp))   
     for(int i=1;i<=n;i++)
          for(int j=0;j<=C;j++)
          {
               if(i==1)
                    dp[i][j]=0;
               if(j>=V[i])
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-V[i]]+W[i]);
          } cout<<dp[n][C]<<endl;
     return 0;
}

其中的可以不需要保存V[i]和W[i]的,可以直接输入直接进行运算:

for(int i=1;i<=n;i++)
{
          cin>>V>>W
          for(int j=0;j<=C;j++)
          {
               if(i==1)
                    dp[i][j]=0;
               if(j>=V[i])
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-V]+W);
          }
}

更奇妙的是可以把它变成维数组:

for(int i=1;i<=n;i++)
{
          cin>>V>>W;
          for(int j=C;j>=0;j--)
          {
               if(i==1)
                    dp[i][j]=0;
               if(j>=V[i])
                    dp[j]=max(dp[j],dp[j-V]+W);
          }
}

对于变成一维数组就感觉很神奇,但是自己不是很能理解为什么可以,就先留着疑问吧,以后在接触到其他的加以理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值