2602--0-1背包

Problem Description

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

Input

The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.

Output

One integer per line representing the maximum of the total value (this number will be less than 231).

Sample Input

1
5 10
1 2 3 4 5
5 4 3 2 1

Sample Output

14


因为所求问题是n件物品,背包限重为m,随着问题规模的增减,n 和m都在变化,因此很自然地想到把件数和背包限重都作为自变量。定义函数f(i,j)为在1~I 件物品中选若干件装入限重为j的背包中的最大价值和。

当第I件物品要装入背包时,f(I,j) := I-1件物品,限重为j-w[I]的最优解+ v[I], 即:f(I,j) := f(I-1, j-w[I]) + v[I]
当然,第I件物品要装入是有条件限制的,是什么?
第I件物品重量小于等于背包限重,即 w[I] <= j
当第I件物品不装入背包时,f(I,j) := I-1件物品,限重为m的最优解,即:
f(I,j) := f(I-1, j)
现在已经求得装入或者不装入第I件物品的限重为J的背包的最大价值,那么接下来应该做什么?
比较这两种情况下谁的价值更大,更大者为当前问题的最优解。
if f(I,j)’ > f(I,j)’’ then
f(I,j) := f(I,j)’
else
f(I,j) := f(I,j)’’;
上述递归式的边界条件是什么?
我们知道f(I,j)的I和J都有一个取值范围。1<=I<=n, 0 <=J<=m. 边界条件就是当问题规模缩小到自变量下界时的函数的取值情况。
当背包限重为0时,无法放任何物品,此时所有的f(I,0) := 0 (1<=I<=n). 这就是边界条件。


解1:二维数组

#include<cstdio>
#include<algorithm>
using namespace std;

int dp[1005][1005] = {0};
/*dp[i][j]为在1~I 件物品中选若干件装入限重为j的背包中的最大价值和。*/
int main()
{
    int t;
    scanf ("%d",&t);

    while (t--)
    {
        int n,v;
        scanf ("%d%d",&n,&v);

        int value[1005],volume[1005];

        for (int i=1; i<=n; i++)
        {
            scanf ("%d",&value[i]);
        }

        for (int i=1; i<=n; i++)
        {
            scanf ("%d",&volume[i]);
        }

        for (int i=1; i<=n; i++)
        {
            for (int j=0; j<=v; j++)
            {
                if (j < volume[i])
                {
                    dp[i][j] = dp[i-1][j];
                }
                else
                {
                    dp[i][j] = max(dp[i-1][j],dp[i-1][j-volume[i]]+value[i]);
                }
            }
        }
        printf ("%d\n",dp[n][v]);
    }
    return 0;
}

二维数组最重要的一点是要注意数组开辟的空间,由于这道题的要求,1005*1005将会占大片空间,所以要定义在主函数外。


解2 :一维数组

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int main()
{
    int t;

    scanf ("%d",&t);

    while (t--)
    {
        int n,v;
        int value[1005],volume[1005];
        int i,j;

        scanf ("%d%d",&n,&v);

        for (i=0; i<n; i++)
        {
            scanf ("%d",&value[i]);
        }

        for (i=0; i<n; i++)
        {
            scanf ("%d",&volume[i]);
        }

        int dp[1005] = {0};

        for (i=0; i<n; i++)
        {
            for (j=v; j>=volume[i]; j--)
            {
                dp[j] = max(dp[j],dp[j-volume[i]]+value[i]);
            }
        }

        printf ("%d\n",dp[v]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值