完全背包问题

时间:2022-04-10 04:22:30

完全背包问题

题目 :

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

算法分析:

此题跟01背包相似,所不同的是物品无无限件,考虑到第i种物品最多选V/c[i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品,然后求解这个01背包问题。

状态转移方程:f[i][v]=max{f[i-1][v-K*c[i]]+k*w[i]|k*c[i]<=v}

伪码:

              for i=1..N

                     for v=0..V

                            f[v]=max{f[v],f[v-c[i]]+w[i]}

注意:此处v的循环次序和01背包的循环次序不同!!!

原因:01背包发f[i][v]是根据状态发f[i-1][v-c[i]]递推过来的,而现在完全背包每件物品可选无限件,所以在考虑“加选一件第i种物品”的策略时,却正需要已选入第i个物品子结果发f[i][v-c[i]]。

简单优化:

1)若两件物品i、j满足c[i]<=c[j]    并且w[i]>=w[j],则将物品j去掉,不用考虑 .

2)将费用大于V的物品去掉 .

 

 

实现代码:

#include<bits/stdc++.h>
using namespace std;
struct goods
{
    int c,w;          //c为价钱,w为价值
}goods[10000];
int main()
{
    int n,v,i,j;
    int f[1000];
    cin>>n>>v;           //n为物品数,v为价钱容量
    for(i=0;i<=v;i++)   //背包不要求装满
        f[i]=0;
  for(i=0;i<n;i++)
  cin>>goods[i].c>>goods[i].w;
  for(i=0;i<n;i++)
  {
      for(j=goods[i].c;j<=v;j++)
        if(f[j]<f[j-goods[i].c]+goods[i].w)   //重要条件
         f[j]=f[j-goods[i].c]+goods[i].w;

  }
  cout<<f[v]<<endl;
  return 0;
}