2021-05-08

完全背包问题

意思大概是
有N件物品,每件物品的重量为w[i],价值为c[i],现有一个容量为V的背包,问如何选取物品放入背包中,使得物品的总价值最大。其中每种物品都有无穷件。

#include
#include
using namespace std;

int c[100],w[100];//c:存储价值 w存储消耗的容量
int dp[100][100];//第一维:标号 第几件物品 第二维:当前容量
// 整个DP数组表示的值是前i件物品恰好装入容量为v的背包中所能获得的最大价值
int V,N;

int main()
{
cin>>N>>V;
for(int i=1;i<=N;i++)
{
cin>>w[i]>>c[i];//从1开始输入,0当作第一个的前面边界,为0
}
//dp[0][k]为边界,若定义的局部变量应赋值为0,但此处为全局变量,已经初始化
for(int i=1;i<=N;i++)
{
for(int k=w[i];k<=V;k++) //从0开始枚举容量 ,恰好装入容量为K,其获得的最大值
{
dp[i][k]=max(dp[i][k],dp[i][k-w[i]]+c[i]);//两种策略 不放第i件物品 和放入第i件物品 在这里插入代码片
}
}
//最后应找到所有容量中最大价值值,故应该枚举容量找到最大值,但其实上述有继承效果,最大的dp[最后一件物品][最大容量]即为最大值
cout<<dp[N][V]<<endl;
return 0;
}
发现与01背包不同的是
第2重循环
01背包 for(int j=v;j>=w[i];j–)枚举容量从后往前来;
完全背包 for(int j=w[i];j<=v;j++) 枚举容量从前往后来;
dp[][]维数
其实dp数组的维数优化后都可以用一维来表示;
01 dp[k]=max(dp[k],dp[k-w[i]]+a[i]
完全 dp[k]=max(dp[k],dp[k-w[i]]+a[i])
虽然两者优化后状态方程一样 但是第2重循环不同 所以结果不一样

下面是01背包变形的例题(完全背包的题还没做到)
电科大诡异饭卡
关键思路:·饭菜可以选择买或者不买,为了购买总价值最多的饭菜,先从余额中取出五块钱买最贵的

sort(a+1,a+t+1);   菜钱排序,先买贵的

        cin>>q;
        b=q-5;5快钱买最贵的
        
      for(int i=1;i<t;i++)
            for(int j=b;j>=a[i];j--)

                  dp[j]=max(dp[j],dp[j-a[i]]+a[i]);

                  if(b<0)cout<<q<<endl;
                  else cout<<q-dp[b]-a[t]<<endl; 
                   总价钱-最贵的菜总价-最贵的菜;

例题2

最近,伊西去了一个古老的国家。在这么长的一段时间里,它是世界上最富有和最强大的王国。因此,这个国家的人民仍然非常自豪,即使他们的国家已经不再那么富有了。商人是最典型的,每个人只卖一件商品,价格是PI,但如果你的钱低于qi,他们会拒绝和你做交易,而Isea评估每一件物品都是价值Vi。如果他有M个单位的钱,我能得到的最大价值是什么?
bool cmp(itm a,itm b)
{
    return a.q-a.p<b.q-b.p;
    }
    sort(it,it+n,cmp);
        for(i=0;i<n;i++)
            for(j=m;j>=it[i].q;j--)
            dp[j]=max(dp[j],dp[j-it[i].p]+it[i].v);
        cout<<dp[m]<<endl;

思路关键:设,q1 B:p2,q2,如果先A后B,则至少需要p1+q2的容量,如果先B后A,至少需要p2+q1的容量,那么就是p1+q2 > p2+q1,变形之后就是q1-p1 < q2-p2。
‘这个题不能直接dp
因为如果一个物品是2,3一个物品是2,2,对第一个进行背包的时候只有dp[3],dp[4],…,dp[m]有值。再对第二个进行dp的时候,应该会借用前面的dp[1],dp[2]之类的,但是现在这些值都是0,所以会导致结果出错;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值