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

来源:互联网 发布:mysql in 编辑:程序博客网 时间:2024/06/15 17:19



这道题完全就是一个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