1. 程式人生 > >01揹包詳解

01揹包詳解

01揹包 給定一個容量為c的揹包,有n個物品,第i個質量為wi,價值為vi,求揹包的最大價值

由於每種物品只有1個,因此每個物品只有01兩種狀態,即拿和不拿 用V【i,j】表示在面對第i個物品且揹包容量為j時,揹包內的最大價值

那麼顯然,V【0,j】和V【i,0】都應該初始化為 解決問題時有兩種情況, (1)當前揹包容量不足以放入i(j<wi),那麼V【i,j】=V【i-1,j】 (2)當前揹包容量足以放入i(j>=wi),此時要選擇i放還是不放,如果不放V【i,j】=V【i-1,j】;如果放V【i,j】=V【i-1,j-wi】+vi。取兩者之間的那個較大的值 狀態轉移方程

if(j>=w[i])
    m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
else
    m[i][j]=m[i-1][j];

0 1 2 3 4 5 6 7 8 9 10 11 12
0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 8 8 8 8 8 8 8 8 8
2 0 0 0 0 8 8 10 10 10 10 18 18 18
3 0 0 6 6 8 8 14 14 16 16 18 18 24
4 0 0 6 6 9 9 14 14 17 17 19 19 24
5 0 0 6 6 9 9 14 14 17 17 19 21 24
6 0 2 6 8 9 11 14 16 17 19 19 21 24

程式碼: (程式碼是以6個物品為例的)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <algorithm>
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define PI acos(-1)
typedef long long ll;
int dp[7][10000+5];
int w[7];
int v[7];
int main()
{
    int t,m;
    scanf("%d",&t);
 
    while(t--)
    {
        memset(dp,0);
        scanf("%d",&m);
        for(int i=1; i<=6; i++)
            scanf("%d",&w[i]);
        for(int i=1;i<=6;i++)
            scanf("%d",&v[i]);
        for(int i=1; i<=6; i++)
            for(int j=1; j<=m; j++)
            {
                 if(j<w[i])
                    dp[i][j]=dp[i-1][j];
                 else
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
            }
        printf("%d\n",dp[6][m]);
    }
}