网易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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值