HDU-Bone Collector(背包问题中的小细节)



这道题完全就是一个01背包问题,一般同样的题我不写两边的,浪费时间,浪费精力,

但是为什么这道题我就写了两遍?

因为我发现一个问题是我以前所未发现的

我首先按照以前的思路写的第一次

#include<stdio.h>
#include<string.h>
int m[1000],v[1000];
int dp[1005][1005];
int max(int a,int b)
{
    if(a>=b)
        return a;
    else
        return b;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,v0,num=0;
        scanf("%d%d",&n,&v0);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&v[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&m[i]);
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            for(int j=m[i];j<=v0;j++)
            {
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]+v[i]);
            }
        }
        
        printf("%d\n",dp[n][v0]);
    }
    return 0;
}

看着没毛病

提交WA

来一组数据你就知道了

5  0

2  4  1  5  1

0  0  1  0  0

正确的应该输出12

但是上面的代码输出的是6

下面上一个AC代码

#include<stdio.h>
#include<string.h>
int m[1000],v[1000];
int dp[1005][1005];
int max(int a,int b)
{
    if(a>=b)
        return a;
    else
        return b;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,v0,num=0;
        scanf("%d%d",&n,&v0);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&v[i]);
        }
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&m[i]);
        }
        memset(dp,0,sizeof(dp));
        for(int i=1; i<=n; i++)
        {
            for(int j=0; j<=v0; j++)
            {
                if(j>=m[i])
                {
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]+v[i]);
                    //printf("%d %d*\n",dp[i-1][j],dp[i-1][j-m[i]]+v[i]);
                }
                else
                {
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        printf("%d\n",dp[n][v0]);
    }
    return 0;
}

这个就可以,给的数据输出为12,再看看两个的差别

就是动规的那一点

第一个

for(int i=1;i<=n;i++)
        {
            for(int j=m[i];j<=v0;j++)
            {
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]+v[i]);
            }
        }

第二个

for(int i=1; i<=n; i++)
        {
            for(int j=0; j<=v0; j++)
            {
                if(j>=m[i])
                {
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]+v[i]);
                    //printf("%d %d*\n",dp[i-1][j],dp[i-1][j-m[i]]+v[i]);
                }
                else
                {
                    dp[i][j]=dp[i-1][j];
                }
            }
        }

其实就是防止当j<m[ i ] 的时候访问到不该访问的区间

按理说第一个第二个都可以达到这样的效果

但是第一个 在判断数据 2  4 后就停止

输出结果是2

到底是哪里出了问题那?

打印出来一下过程

第一个

1
5 0
2 4 1 5 1
0 0 1 0 0
2
6
0
5
6
6

 

第二个

1
5 0
2 4 1 5 1
0 0 1 0 0
2
6
6
11
12
12

当到了第三件物品的时候打表出来的结果是 0 从这开始就错了

按理说应该是6啊;

为啥啊?  其实也很好解释当 第三件物品的时候,for循环根本就没进去,所以导致打表的第三行就没进行运算

意思说前面的背包装的都扔了,作废了 又从零开始了

由此可以推理出 如果压缩成一维的话,两种情况应该都对,因为压缩成一维了,一维只动后面的数,数组里面本来就留着上次运算的最优解

不会出现没进行运算就变为0的情况

那个01背包的题两种方法都OK,估计是题目说的背包体积大于0吧

如果背包体积大于零两种都可以了






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值