首页 > 其他 > 详细

01背包

时间:2020-05-29 18:33:25      阅读:40      评论:0      收藏:0      [点我收藏+]

一、 问题描述

     有n件物品,每件物品都只有一件,每件物品的重量为w[i],价值为v[i],现在有一个容量为V的背包,问如何选取物品放入背包,使得背包内的物品的总价值最大?

此时,我们举个例子:设一共有4件物品,背包的容量为8,每件物品的质量和价值分别为  2  3,3  4,4 5,5 6,求该背包最大能装的物品的价值是多少?

二、问题解决

    首先对于一个物品,我们对它的命令就只有两个,要么放入背包(就是1),要么不放进背包(就是0)。

那么我们设置一个二维数组dp[i][j],用它来表示:当放入第 i 件物品,且空间为 j 时存放的物品的最大价值。

此时我们的 dp[i][j]=max(dp[ i - 1 ] [ j ] , dp [ i - 1 ][ j - w [ i ] ] + v [ i ]),前面的dp[ i - 1 ] [ j ]表示在不放第 i 件物品时的最大价值,后面的 dp [ i - 1 ][ j - w [ i ] ] + v [ i ]   表示在不放入这个物品时,背包刚好能放入该物品的重量 的 最大价值,再把该物品放入背包,再加上 v [ i ],即放入该物品的最大价值。

 

技术分享图片
#include<stdio.h>
#include<stdlib.h>
int w[105],v[105],dp[105][105];
int max(int a,int b)
{
    if (a>b) return a;
    else return b;
}
int main()
{
    int  i,n,m,j,k,V;
    double b;
   scanf("%d%d",&n,&V);
   for (i=1;i<=n;i++)
   {
       scanf("%d%d",&w[i],&v[i]);
   }
   for (i=0;i<=n;i++)
    {
      for (j=1;j<=V;j++)
      {
          if (j<w[i]) dp[i][j]=dp[i-1][j];
          else  dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
          printf("%d ",dp[i][j]);
      }
      printf("\n");
    }
   return 0;
}
View Code

 

话不多说,我们直接上图来解释:

技术分享图片

 但是实际上我们可以从上面的表格中看到,我们用二维数组存储了第一行的数据,但实际上只在第二行用到了第一行的数据,在这之后就没有再用了,所以第 i 行的数据只是在第 i+1行用到了,用完之后没有用放在数组里面也占用了极大地空间,所以我们使用一个“滚动数组”来实现这种操作。所谓的滚动数组就是利用一维数组,把第i+1行的数据覆盖在第i行上面,于是就变成了:

 

技术分享图片
#include<stdio.h>
#include<stdlib.h>
int w[105],v[105],dp[105];
int max(int a,int b)
{
    if (a>b) return a;
    else return b;
}
int main()
{
    int  i,n,m,j,k,V;
    double b;
   scanf("%d%d",&n,&V);
   for (i=1;i<=n;i++)
   {
       scanf("%d%d",&w[i],&v[i]);
   }
   for (i=1;i<=n;i++)
    {
      for (j=1;j<=V;j++)
      {
      if (j>=w[i]) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
          printf("%d ",dp[j]);
      }
      printf("\n");
    }
   return 0;
}
View Code

 

 技术分享图片

 

 

 非常奇怪,为什么这样的结果和上面算出来的不一样呢? 观察这里的数据我们可以看出,在计算dp [ 1 ] [ 4 ]时,是在原先放了一个w[1 ]的基础上再放一个w [ 1 ],这样它就放了两次,不符合我们01背包的规则, 那么我们该怎么做呢?其实很简单,只需要从打到小放置就可以了,即从V开始一直到w [ i ] 为止,这样就很好的解决了这个问题,到此,01背包的问题也算是圆满完成了,以下附上代码:

技术分享图片
#include<stdio.h>
#include<stdlib.h>
int w[105],v[105],dp[105];
int max(int a,int b)
{
    if (a>b)
        return a;
    else
        return b;
}
int main()
{
    int  i,n,m,j,k,V;
    double b;
    scanf("%d%d",&n,&V);
    for (i=1; i<=n; i++)
    {
        scanf("%d%d",&w[i],&v[i]);
    }
    for (i=1; i<=n; i++)
    {
        for (j=V; j>=w[i]; j--)
        {
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
        for (j=1; j<=V; j++)
        {
            printf("%2d ",dp[j]);
        }
        printf("\n");
    }

    return 0;
}
View Code

 

技术分享图片

 

01背包

原文:https://www.cnblogs.com/ypw1131115630/p/12988766.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!