和上个01背包相似。
这个完全背包的不同在于,对于一个物品,可以对面无数次。
所以我直接再昨天的程序上进行一个小改动就行了。
先放出昨天01背包的代码:ans是一个用来记忆化的数组并事先清0。
int f()
{
for(int n=0;n<N;n++)
for(int i=M;i>=need[n];i--)
{
int t1=ans[i];
int t2=ans[i-need[n]]+value[n];
ans[i]=t1>t2?t1:t2;
}
return ans[M];
}
因为在01背包的时候物品只能兑换一个,递推式子为:
ans(n,m)=max{ans(n-1,m),ans(n-1,m-need(n))+value(n)}
所以在计算的时候从M循环到need[n],这样就不会出现多个选择的情况。
而在完全背包的时候,物品能兑换多个,递推式子为:
ans(n,m)=max{ans(n-1,m),ans(n,m-need(n))+value(n)}
所以在计算的时候只要从need[n]循环到M就好了,这样就在计算的时候就会出现选择多个的情况。
即完全背包的全代码为:
#include<cstdio>
#include<cstring>
using namespace std;
int N,M;
int need[501],value[501];
int ans[100001];
int f()
{
for(int n=0;n<N;n++)
for(int i=need[n];i<=M;i++)
{
int t1=ans[i];
int t2=ans[i-need[n]]+value[n];
ans[i]=t1>t2?t1:t2;
}
return ans[M];
}
int main()
{
memset(ans,0,sizeof(ans));
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++)
scanf("%d%d",&need[i],&value[i]);
printf("%d",f());
return 0;
}