01背包 hiho一下第 6 周

6 篇文章 0 订阅

题意: 经典的 01 背包问题

思路: 基本的做法是用 best[i][j] 表示前 i 个奖品在奖券小于等于 j 的情况下能达到的最大喜好值。每个奖品都有取或不取两种状态,取的时候奖券变少,喜好值增加;不取的时候奖券和喜好值都不变。所以此时的状态转移方程式为

best[i][j]=max(best[i1][j],best[i1][jneed(i)]+value[i])

写成代码为:

memset(best[0], 0, sizeof(best[0]));
for(int i=1; i<=N; i++){
    for(int j=0; j<=M; j++){
        if(j < need[i]) best[i][j] = best[i-1][j];
        else best[i][j] = max(best[i-1][j], best[i-1][j-need[i]]+value[i]);
    }
}

由状态转移式我们可以看出求 best[i][j] 时只与第 i-1 行有关系,所以这里继续进行优化以减少空间。
当我们把第二层循环反过来时,也就是从 M 到 0 进行遍历时,会发现 best[i][j] 的值是从右往左计算的,而计算时只与当前位置的 best[i-1][j] 和左边的 best[i-1][j-need[i]] 有关,所以这边又可以进行空间上的优化,使得只需要 O(M) 的空间复杂度。
又从 need[i] 遍历到 0 时 best[i][j] 的值就等于 best[i-1][j] 的值,所以可以不需要进行遍历。
优化的代码见下列程序。

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
typedef long long LL;

int N, M;
int need[550];
int value[550];
int best[100010];

int main()
{
    while(scanf("%d%d", &N, &M) == 2){
        for(int i=1; i<=N; i++){
            scanf("%d%d", &need[i], &value[i]);
        }

        memset(best, 0, sizeof(best));
        for(int i=1; i<=N; i++){
            for(int j=M; j>=need[i]; j--){
                best[j] = max(best[j], best[j-need[i]]+value[i]);
            }
        }

        printf("%d\n", best[M]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值