FZU - 2214 Knapsack problem (零一背包 变形)

该博客讨论了FZU的一道关于零一背包问题的题目,指出当物品重量过大可能导致数组溢出的问题。博主提出通过调整价值和重量的位置,重新定义dp状态来避免溢出,并利用背包算法求解。对于是否需要恰好装满背包的情况,博主给出了不同的初始化策略来确保找到最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

iven a set of n items, each with a weight w[i] and a value v[i], determine a way to choose the items into a knapsack so that the total weight is less than or equal to a given limit B and the total value is as large as possible. Find the maximum total value. (Note that each item can be only chosen once).

Input

The first line contains the integer T indicating to the number of test cases.

For each test case, the first line contains the integers n and B.

Following n lines provide the information of each item.

The i-th line contains the weight w[i] and the value v[i] of the i-th item respectively.

1 <= number of test cases <= 100

1 <= n <= 500

1 <= B, w[i] <= 1000000000

1 <= v[1]+v[2]+...+v[n] <= 5000

All the inputs are integers.

Output

For each test case, output the maximum value.

Sample Input

1
5 15
12 4
2 2
1 1
4 10
1 2

Sample Output

15

刚看发现是01背包板子题,兴奋的敲一发,RE,wtf……(''^_^)!!

题目w太大会导致数组溢出。不过注意到价值的数据较小。可以将物品的价值和体积位置调换,dp[j]的含义改变为装价值为j的的物品,至少需要多大的容量。运用背包求解(注意:此处的01背包要求恰好装满),求出最后各个价值所需的最小容量,然后通过与限制B进行比较,求出最大容量。

初始化问题:有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背 包装满。如果是第一种问法,要求恰好装满背包,那么在初始化时除了F[0]为0,其 它F[1..V ]均设为−∞,这样就可以保证最终得到的F[V ]是一种恰好装满背包的 最优解。 如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该 将F[0..V ]全部设为0
 

/*

*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <map>
#include <vector>
#include <set>
#include <bitset>
#include <stack>
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const ll mod=100000007;
const double pi=acos(-1);
const int N=200007;
int a[5009],w[5009],v[5008];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
       mems(a,inf);
       a[0]=0;
       ll sum=0;
       int n,m;
       scanf("%d%d",&n,&m);
       for(int i=1;i<=n;i++)
       {
           scanf("%d%d",&w[i],&v[i]);
           sum+=v[i];
       }
       for(int i=1;i<=n;i++)
       {
           for(int j=sum;j>=v[i];j--)
            a[j]=min(a[j],a[j-v[i]]+w[i]);
       }
       for(int j=sum;j>=0;j--)
       {
           if(a[j]<=m)
           {
               printf("%d\n",j);
               break;
           }
       }
    }
    return 0;
}
/*

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值