POJ 3628 Bookshelf 2(DP:01背包)

本文详细解析了 POJ3628 Bookshelf2 的解题思路,采用01背包问题的动态规划方法解决该题目。通过调整问题目标,将原问题转化为求解背包最大价值与剩余价值之差的问题,并给出了一种高效的实现方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ 3628 Bookshelf 2(DP:01背包)

http://poj.org/problem?id=3628

题意:有N个数字和一个H上限,问你这N个数字怎么取(每个取或者不取)可以使得被取的数总和最小且超过N.求这个最小和与N的差值.

分析:N个数字的和为S且S肯定>=H,我们只需要令X=S-H,然后求背包容量(这里的容量指的是数的价值和不超过X)为X的背包最多能放多少价值,那么剩下的那部分没放的数价值和就肯定>=H且最小.

所以求出容量X的背包能放的最大价值-X的绝对值就是所求.

d[i][j]=x表示放完前i个数容量不超过j能获得的最大和值为x.

d[i][j] =max(d[i-1][j],d[i-1][j-wi]+wi).j>=wi,wi为第i个数的值

初值为:d=0,要用滚动数组

程序实现有两个地方需要注意:

1.    memset(d,0,sizeof(d)); 这句如果加了就会超内存,不明白?

2.    循环时j的下界是W[i],而不是0.

AC代码:0ms

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN=20000000+1;
int w[30],d[MAXN];
int main()
{
    int n,h;
    while(scanf("%d%d",&n,&h)==2)
    {
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
            sum +=w[i];
        }
        //memset(d,0,sizeof(d));//这句不注释掉就会超内存?为什么
        int m=sum-h;
        for(int i=1;i<=n;i++)
        {
            for(int j=m;j>=w[i];j--)//这里注意细节,j的下限是w[i]
            {
                if(j>=w[i]) d[j] = max(d[j],d[j-w[i]]+w[i]);
            }
        }
        printf("%d\n",m-d[m]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值