網易2019筆試題-牛牛的揹包

題目解析

  1. 核心思路
    物品有n個,每個體積爲 v[i],揹包體積爲 w. 每個物品有兩種選擇:放進揹包,不放進揹包。
    狀態設計:f(i,j):物品爲前i個物品,揹包體積爲j,一共多少种放法。
    狀態轉移:
    如果第i個物品放進揹包:f(i-1,j-v[i])
    如果第i個物品不放進揹包:f(i-1,j)
    因此:
    f(i,j) = f(i-1,j-v[i]) + f(i-1,j)

  2. 難點分析:本題的數據量太大,1 <= w <= 2 * 10^9,空間消耗太大。同時,1 <= n <= 30,可以考慮時間換空間,用函數遞歸。

  3. 優化時間複雜度
    不作優化,AC率爲80%。
    設 total 爲所有物品體積之和,如果 total <= w,直接返回 2^n. 優化後,時間大幅降低,爲 4ms.

  4. C++代碼

#include <iostream>
#include<math.h>

using namespace std;
int n, v[32];   // n 表示物品的數量,v表示每個物品的體積
int w;  // 揹包的容量
typedef long long bint;
bint f(int n, int w) // n 表示前 n 個物品, w 表示 揹包體積
{
    if( w ==0 ) return 1;
    if( n == 1 ) {
        if( w < v[n] )
            return 1;   // 不放
        else
            return 2;
    }
    else if( w >= v[n] )
        return f(n-1,w) + f(n-1,w-v[n]);
    else
        return f(n-1,w);
}


int main()
{
    scanf("%d%d",&n,&w);
    bint total = 0;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&v[i+1]);   // 下標從1開始
        total += v[i+1];
    }

    /************** 揹包問題:多少種方法 ****************/
    // dp[i][j]: 使用前i個物品,揹包體積爲j時,有多少种放法
    // 狀態轉移方程:
    // 如果第 i 個物品放進去,  有 dp[i-1][j-v[i]] 种放法
    // 如果第 i 個物品不放進去,有 dp[i-1][j] 种放法
    // dp[i][j] =  dp[i-1][j-v[i]] + dp[i-1][j]
    // 初始化:
    // if j =0, dp[i][j] = 1
    // if i =1, 討論 v[1] 和 j 之間的關係
    bint rs =0;
    if( total <= w )
       rs = (bint)pow(2,n);
    else
       rs = f(n,w);

    cout << rs << endl;

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章