又见01背包
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W 的物品,求所有挑选方案中物品价值总和的最大值。
1 <= n <=100
1 <= wi <= 10^7
1 <= vi <= 100
1 <= W <= 10^9
输入
多组测试数据。
每组测试数据第一行输入,n 和 W ,接下来有n行,每行输入两个数,代表第i个物品的wi 和 vi。
输出
满足题意的最大价值,每组测试数据占一行。
样例输入
4 5
2 3
1 2
3 4
2 2
样例输出
7
来源
飘谊系列
上传者
TC_张友谊
题意
01背包
思路
传统的01背包是每次检查在负重为j的情况下当前背包可以装载的最大价值,在本题当中无疑背包负重极大,这样操作不可行
不过背包的最大价值并不大,我们可以考虑另外一种情况下的装载方式
我们让背包dp里面的数值为在价值为j情况下的最小重量,这样一来我们可以根据传统的01背包的模型构建出一个新的状态转移方程
dp[j] = min(dp[j],dp[j - val[i]] + wei[i]);
自然,在相同价值的情况下,背包的重量越少越好,所以我们这样子是可行的。
那么,我们最后只要使用所有物品的最大价值向下遍历(因为我们就是拿价值当dp数组的索引)直到找到一个dp当中的重量满足背包的最大容量,那么此时的价值就是最大价值。
坑点
无。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 50000
#define inf 0x3f3f3f3f
int dp[maxn];
int wei[maxn],val[maxn];
void solve(void)
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int valsum = 0;
for(int i = 0 ; i < n ; i++)
{
scanf("%d%d",&wei[i],&val[i]);
valsum += val[i];
}
memset(dp,inf,sizeof dp);
dp[0] = 0;
for(int i = 0 ; i < n ; i++)
{
for(int j = valsum ; j >= val[i] ; j--)
{
dp[j] = min(dp[j],dp[j - val[i]] + wei[i]);
}
}
for(int i = valsum ; i >= 0 ; i--)
{
if(dp[i] <= m)
{
printf("%d\n",i);
break;
}
}
}
}
int main(void)
{
solve();
return 0;
}