C-完全背包
时间限制: 1 Sec 内存限制: 64 MB
题目
题目描述
(背景很复杂,就是一个裸的完全背包)。
输入
第一行:背包容量
W
物品个数
后面几行:物品价值
b[i]
物品重量
w[i]
( 0≤w[i],b[i]≤W,N≤10000 )
输出
一行,答案。
样例输入
300 4
100 60
250 120
120 100
35 20
样例输出
605
分析
这里直接从01背包的滚动数组上进行类比。
为什么01背包要逆序循环
举个例子:
假设
f
数组中是这样的:
1 2 3 4 5
如果是正序的,当
6 7 8 4 5
但是
f[j]
需要从
f[j−w[i]]
进行转移,而且要保证
f[j−w[i]]
是
f[i−1][w[i]]
的值。
如果是正序的,显然当
j=4
时,
f
数组已经变成了这样:
也就是说此时的
f[j−w[i]]
一定表示的是
f[i][j−w[i]]
的值,而不是
f[i−1][j−w[i]]
的值了。
而逆序循环就没有这个问题。
完全背包正序循环即可
当正序循环
j=4
时,
f
数组是这样的:
也就是说,
f[j−w[i]]
表示的是
f[i][j−w[i]]
(允许我重复说一遍),想一下它的意义是什么呢:前
i
个物品,背包容量为
代码
#include<cstdio>
#include<algorithm>
using namespace std;
int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
#define MAXN 10000
#define MAXW 10000
int w[MAXN+5],b[MAXN+5];
int f[MAXW+1];
int N,W;
int main()
{
W=read(),N=read();
for(int i=1;i<=N;i++)
b[i]=read(),w[i]=read();
for(int i=1;i<=N;i++)
for(int j=0;j<=W;j++)//正序循环
if(j>=w[i]&&f[j]<f[j-w[i]]+b[i])
f[j]=f[j-w[i]]+b[i];
printf("%d\n",f[W]);
}