完全背包不同于01背包的是每种物品可以放无限多次。
题目
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本思路
子问题定义:F[i][j]表示前i种物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值。
设物品种数为n,背包容量为c,第i种物品的体积和价值分别为为w【i】,v【i】。
状态转移方程dp[i][j]=max(dp[i][j],dp[i-1][j-k*need[i]]+k*value[i]);
其中f[i-1][j-k*w[i]+k*v[i]表示前i-1种物品选若干物品放入剩余空间为j-k*w[i]的背包中所能达到的最大价值以及加上第i种物品所能达到的最大总价值。
#include<bits/stdc++.h>
using namespace std;
int dp[600][10010];
int a[600],b[600];
int main(){
int i,j,k;
int n,m;
while(~scanf("%d %d",&m,&n)){
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
scanf("%d %d",&a[i],&b[i]);
for(i=1;i<=n;i++)
for(j=0;j<=m;j++)
for(k=0;k*a[i]<=j;k++)
dp[i][j]=max(dp[i][j],dp[i-1][j-k*a[i]]+k*b[i]);
printf("%d\n",dp[n][m]);
}
return 0;
}
我们会发现内存消耗太大,时间也比较长。我们可以优化一下。在01背包中之所以使用逆序循环,保证更新dp[j]的时候dp[j-W[i]]是没有放入物品i时的数据dp[i-1][j-W[i]] 。
这是因为01背包中每个物品至多只能被选择一次。
而在完全背包中每个物品可以被无限次选择,固在这里将遍历顺序改为顺序,因为先序可以使我们在这次判断是否再放入时已经保证已经放入了若干或暂时还为放入该种物品。使在更新状态dp[j]的时候,dp[j-W[i]]时可能因为放入物品i而发生改变,从而得到目的简单讲就是把01背包从逆序改成顺序就是完全背包
#include<bits/stdc++.h>
using namespace std;
int dp[10010];
int a[600],b[600];
int main(){
int i,j,k;
int n,m;
while(~scanf("%d %d",&m,&n)){
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
scanf("%d %d",&a[i],&b[i]);
for(i=1;i<=n;i++)
for(j=a[i];j<=m;j++)
dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
printf("%d\n",dp[m]);
}
return 0;
}