hdu 2602 - Bone Collector

1. 地址

http://acm.hdu.edu.cn/showproblem.php?pid=2602

2. 定位

  • 动态规划

  • 0-1背包

3. 分析

3.1 典型0-1背包

状态转移方程为 dp[i,v]=max(dp[i1,v],dp[i1,vvolume[i]]+value[i])

dp[i,v] 表示前 i 件物品经选择后放入容量为 v 的背包中获得的最优解(总价格最大),该值可以在前 i1 件物品最优解的基础上得到:

  • 不放入第 i 件物品,即 dp[i,v]=dp[i1,v]

  • 放入第 i 件物品,同时为其加入腾出足够的空间容量,即 dp[i,v]=dp[i1,vvolume[i]]+value[i]

放入第 i 件物品可能意味着在前i1 件物品中少放入部分物品,丢西瓜捡芝麻。因此,二者比较取最大值即为问题的最优解。

3.2 存储空间优化

分析状态转移方程, dp[i,v] 仅与 dp[i1,v] dp[i1,vvolume[i]] 有关,采用二维数组完整地存储 dp[1][],dp[2][],...,dp[i1][] 是一种存储空间上的浪费,我们需要的只是 dp[i1][] 。另外,由于 dp[i1][x]x<=v ,采用数组逆序更新的方式可以保证上一状态的先使用后更新。

因此,将问题的存储空间由二维数组优化为一维数组,状态转移方程为 dp[v]=max(dp[v],dp[vvolume[i]]+value[i])

3.3 边界处理

dp[0] 看似荒谬,实则是有意义的:

  • vvolume[i] 很容易出现非正数的情况: vvolume[i]<0 说明背包无法容纳第 i 件物品,舍去;vvolume[i]=0 相当于在背包中装入首个物品。

  • dp[0] 表示背包容量为0时背包的总价格,它不一定为0。若某物品体积为0且价格不为0,则背包容量为0时其价格也为正数,这是本题陷阱之一

不论题中有无此陷阱,建议保留 dp[0] ,尽量避免特殊情况的处理,保证算法逻辑的一般性。

4. 代码

#include <stdio.h>
#include <stdlib.h>

#define MAX_N 1001

int volume[MAX_N];
int value[MAX_N];
int dp[MAX_N];

int main()
{
    int T,N,V;
    int i,j;

    scanf("%d*c",&T);
    while(T--)
    {
        scanf("%d*c",&N);
        scanf("%d*c",&V);
        memset(volume,0,sizeof(volume));
        memset(value,0,sizeof(value));
        memset(dp,0,sizeof(dp));
        for(i=1; i<=N; i++)
        {
            scanf("%d*c",&value[i]);
        }
        for(i=1; i<=N; i++)
        {
            scanf("%d*c",&volume[i]);
        }
        for(i=1; i<=N; i++)
        {
            for(j=V; j>=volume[i]; j--)
            {
                dp[j] = dp[j-volume[i]] + value[i] > dp[j] ? dp[j-volume[i]] + value[i] : dp[j];
            }
        }
        printf("%d\n",dp[V]);
    }
    return 0;
}

5. 性能

Exe.TimeExe.MemoryCode LengthLanguage
31MS1516K840Bc

6. 未解决问题

6.1 无符号整型的处理效率

在本题中,将数组声明为无符号整型,运算超时;声明为有符号整型后,则顺利通过。对此,提出以下几点猜想:

  • 无符号数运算耗时

  • memset() 对无符号数的操作耗时

Ver 1.0 2017-9-18

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值