美文网首页
01背包问题

01背包问题

作者: 小幸运Q | 来源:发表于2019-01-03 15:23 被阅读5次

题目: 有限个数的货物,具有不同的体积还有价值,怎么让其放进有限体积的背包并价值最大。

货物只有两种可能,放进去/不放进去,本质上其实就是个1/0二叉树。
利用递归的栈效应根据DFS进行先判断后遍历即可。

NOIP版解法没有使用DFS:http://www.wutianqi.com/?p=539

通过建立数组a[i][j],i表示第几件商品,就表示现在所分配的体积(前i-1件商品可以不全占留一点缝但必须是局部最优组合)。
默认采用 i-1 的组合,但是如果同V条件下添加 i (当然会挤掉一部分物体)可以使总的 value 上升则替换 F[i][j] = F[i - 1][j - C[i]] + W[i];(记得先执行C[i]-j检查是否可以容纳商品i),被替换的原物品在F[i-1][j-C[i]]中已经剔除了。

物品号i    1   2   3   4   5   6
体积C 2   3   1   4   6   5
价值W 5   6   5   1   19  7

最大价值 30

物品数量 总体积
物品体积 物品价值

6 10
2 5
3 6
1 5
4 1
6 19
5 7
#include <bits/stdc++.h>
using namespace std;
int main(){
  int i,j,number,volumn;
  scanf("%d %d",&number,&volumn);

  int weight[100]; //记录每个物品的质量
  int value[100];  //记录每个物品的价值
  int v;
  int f[100][100]; // 记录value的数组

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

  for(i=1;i<number+1;i++){
    scanf("%d",&v);
    weight[i]=v;
  }

  for(i=1;i<=number;i++){
    for(j=0;j<=volumn;j++){
      f[i][j]=f[i-1][j];
      if(weight[i]<=j&&f[i-1][j-weight[i]]+value[i]>f[i][j]){
        f[i][j]=f[i-1][j-weight[i]]+value[i];
      }
    }
  }

  cout<<"打印f数组:"<<endl;
  for(i=1;i<=number;i++){
    for(j=0;j<=volumn;j++){
        cout<<f[i][j]<<"\t";
    }
    cout<<endl;
  }
  cout<<endl;


  cout<<"打印选中的节点:"<<endl;
  // 从最大值按照选值规则一路回退即可。
  j=volumn;
  bool x[100];
  for(i=0;i<=volumn;i++){
    f[0][i]=0;
  }
  for(i=number;i>0;i--){
    if(f[i][j]==f[i-1][j]){
        x[i]=false;
    }
    else{
        x[i]=true;
        j=j-weight[i];
    }
  }

  for(i=1;i<=number;i++){
    cout<<x[i]<<"\t";
  }
  cout<<endl;
  cout<<"最优值:"<<f[number][volumn];
}
image.png

如果不想用DFS而想用更加精简的,可以采用一维数组的方法:

  • 转移方程:f[v]=max{f[v],f[v-c[i]]+w[i]};
#include <bits/stdc++.h>
using namespace std;
int main(){
      int i,j,number,volumn;
      scanf("%d %d",&number,&volumn);

      int weight[100];
      int value[100];
      int v;
      int f[100];
      bool path[100][100]={false};
      for(i=0;i<100;i++){
        f[i]=0;
      }

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

      for(i=1;i<number+1;i++){
        scanf("%d",&v);
        weight[i]=v;
      }

      for(i=1;i<=number;i++){
        // 从后往前写,因为从前往后,j-1不是之前j-1次操作的解而是被覆盖后的j操作的解。
        for(j=volumn;j>=0;j--){
          if(weight[i]<=j){      // 因为一维数组的原因所以可以不用f[j]=f[j-1];因为不动就是默认f[j-1];
            if(f[j-weight[i]]+value[i]>f[j]){
                path[i][j]=true;
                f[j]=f[j-weight[i]]+value[i];
                // f[j]=max(f[j-weight[i]]+value[i],f[j]);  如果不需要打印路径的话
            }
          }
        }
      }
    cout<<endl;
    cout<<"max="<<f[volumn]<<endl;
    cout<<endl;

    cout<<"打印路径(反方向打印): 因为从头开始的话,它无法知道i+1的volmn应该是哪个-->既可以是平移不变也可以是+=weight[i+1]"<<endl;
    for(i=number;i>0;i--){
        // 之前做了path标记的位置就是选中商品的位置
        if(path[i][volumn]==true){
            cout<<1<<"\t";
            volumn-=weight[i];
        }
        else{
            cout<<0<<"\t";
        }
    }
    cout<<"还剩下"<<volumn<<"的空间还没被利用。"<<endl;
}

沿着x/y轴方向单调上升:

image.png image.png

相关文章

  • 动态规划-背包问题

    01背包问题 详解:01背包问题详解链接

  • 背包问题1(01背包)

    N件物品,没见有重量Wi,价值Vi;选其中几件放入容量为M的背包中,求价值的最值。——经典背包问题背包问题分三类:...

  • 01背包问题

    动态规划算法一般用来求解最优化问题,当问题有很多可行解,而题目要求寻找这些解当中的“最大值”/“最小值”时,通常可...

  • 01背包问题

    题目描述:给定 n 个物品和一个容量为 W 的背包,物品 i 的重量是 wi,其价值为 vi 。应该如何选择装入背...

  • 01背包问题

    有n个重量和价值分别为wi,vi的物品。从这些物体中挑选出总重量不超过W的物品,求所有方案中价值总和的最大值。 1...

  • 01背包问题

    A - Bone Collector Many years ago , in Teddy’s hometown t...

  • 01背包问题

    令V(i,j)表示在前i(1<=i<=n)个物品中能够装入容量为就j(1<=j<=C)的背包中的物品的最大价值,则...

  • 01背包问题

    题目:有A(2kg,6$);B(2kg,3$);C(6kg,5$);D(5kg,4$);E(4kg,6$)五种物品...

  • 01背包问题

    题目: 有限个数的货物,具有不同的体积还有价值,怎么让其放进有限体积的背包并价值最大。 货物只有两种可能,放进去/...

  • 背包01问题

    背包01问题 背包01问题是一个经典的算法。 问题是这样描述的:一个背包最大容量为9kg,现在有5个物品,每个物品...

网友评论

      本文标题:01背包问题

      本文链接:https://www.haomeiwen.com/subject/hxnfrqtx.html