1. 程式人生 > >FZU 2214 Knapsack problem (01背包)

FZU 2214 Knapsack problem (01背包)

knapsack i+1 int name cst 轉化 break urn tdi

題意:給你n種物品,每種只有一個,第i種物品的價值為Vi,重量為Wi,把這些物品放入一個重量限制為B的背包中,使得背包內的物品在重量不超過B的前提下,價值盡量大,輸出最大價值

1 <= n <= 500

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

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

思路:我們從範圍中可以看到這個物品的重量和背包所能承受的重量特別大,我們不能使用常規的01背包,我們可以把問題轉化一下,我們定義d(i,j)是把第i個物品裝入限制價值為j的背包中的最小重量,那麽d(i,j)=min{d(i+1,j),d(i+1,j-v[i])+w[i]},然後為了減少內存開銷我們可以把它轉化為滾動數組的模式 d(j)=min{d(j),d(i-v)+w},最後只需要找到滿足重量不大於B的最大價值就可以

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

int main(int argc, char const *argv[])
{
    int t;
    ll dp[5005];
    ll n,B;
    cin>>t;
    while
(t--) { scanf("%lld %lld",&n,&B); memset(dp,INF,sizeof(dp)); dp[0]=0; ll sum=0; for(int i=1;i<=n;i++) { ll v,w; scanf("%lld %lld",&w,&v); sum=sum+v; for(int j=sum;j>=v;j--) { dp[j]
=min(dp[j],dp[j-v]+w); } } for(int j=sum;j>=0;j--) { if(dp[j]<=B) { cout<<j<<endl; break; } } } return 0; }

FZU 2214 Knapsack problem (01背包)