一看就会的01简单背包问题

简介: 一看就会的01简单背包问题

相信大家和我一样,在刚开始写背包问题时因为不会动态规划而无从下手,其实简单背包问题真的很简单,只要你仔细阅读这篇文章,就会很快解决~

题目

给定n种物品和一背包。物品i的重量(体积)是w~i,其价值为v~i,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大。

要求:

* 系统给出的第一个数字是背包容量,第二个数字是物品件数,然后分别给出每件物品的重量,再分别给出每件物品的价值。

* 请依次输出装入背包的物品序号,总重量,总价值。

1.贪心算法

       首先我们想到的是贪心算法,用单位重量的价值的大小来判定此物体是否要放入包中,但是贪心算法不一定是最优解,为什么呢?

比如一个背包的最大容量是100

                    编号 1     2    3    4

一些物体的重量是50 10   60   40

他们的重量分别是50  2    30  40

显而易见单位重量价值排序为1>4>3>2

在贪心算法下,我们在取完1和4以后,在取3时发现超过容量,就不继续往后取u,但是实际上我们的2号物品重量刚好不超,并且还增加了总价值,这就是贪心算法的缺陷所在,他的解并非是最优解

   

 那么贪心算法无法解决,我们就来暴力枚举,枚举法(穷举法)得出来的一定是最优解哦~

2.枚举法

**算法描述(伪代码):**

for (i=0 to 2^n-1)

{

将 i 对应的二进制数按位存放到数组Y中;

尝试按照装包方案y进行装包,则背包中物品的重量为CurWeight, 价值为CurValue;

如果CurWeight>C,则丢弃该方案,继续尝试下一种方案;否则,若该方案优于以前的方案,即如果CurValue>Value,则暂存该方案:即X=Y,Value=CurValue, Weight= CurWeight。 继续循环;

}

       看了上述代码,可能你还会有些迷惑,简单的说,就是利用0与1的性质,取对应着乘以1,不取就对应着乘以0

1.定义W和V数组存放重量和价值,输入背包容量等信息

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
int main()
{
  int c,k,n,i,j,m,V,W,MaxV=0,MaxW=0,count;
  scanf("%d %d", &c, &n);
  int w[1000] = { 0 };
  int v[1000] = { 0 };
  int arr[1000] = { 0 }, x[1000] = { 0 };
  for (i = 0; i < n; i++)
  {
    scanf("%d", &w[i]);
  }
  for (i = 0; i < n; i++)
  {
    scanf("%d", &v[i]);
  }

2.通过枚举取与不取的可能有n的2^n次方种可能,(根据排列组合,n个物体取或不取有2^n种可能性),物品的取与不取正好对应着将0和1分别排列组合的放入一个数组里面。

for (i = 1; i < pow(2, n); i++)
  {
    m = n-1;
    //枚举取与不取,方法就是让对应的价值和重量乘以1或0,此时将0与1放在和价值和重量对应顺序的位置,方便相乘
    for (j = 0; j < n; j++)
    {
      arr[m--] = (1&(i>>j)); 
    }

这里的(1&(i>>j))指的是将i右移j位2进制位以后与1的二进制位取并

3.将每一种1到2^n种可能性比较大小,先判断是否超过容量,在判断是否是最大价值,在每一次放入背包时一定要记得清空背包以便于下一次计算哦~

清空背包以便于下一次计算
    W = 0;
    V = 0;
    //将东西放入背包
    for (k = 0; k < n; k++)
    {
      W += arr[k] * w[k];
      V += arr[k] * v[k];
            背包现在的重量和价值
    }
    //比较是否超过容量
    if (W <= c)
    {
      //比较是否是最大价值
      if (V > MaxV)
      {
        MaxV = V;
        MaxW = W;
        count = 0;
        for (int h = 0; h < n; h++)
        {
          //应题目要求将序号存起来方便打印
          if (arr[h] == 1)
          {
            x[count++] = h+1;
          }
        }
      }
    }
  }

4.打印出结果即可

for (i = 0; i < count; i++)
  {
    printf("%d ", x[i]);
  }
  printf("%d %d", MaxW, MaxV);
}

完整代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
int main()
{
  int c,k,n,i,j,m,V,W,MaxV=0,MaxW=0,count;
  scanf("%d %d", &c, &n);
  int w[1000] = { 0 };
  int v[1000] = { 0 };
  int arr[1000] = { 0 }, x[1000] = { 0 };
  for (i = 0; i < n; i++)
  {
    scanf("%d", &w[i]);
  }
  for (i = 0; i < n; i++)
  {
    scanf("%d", &v[i]);
  }
  for (i = 1; i < pow(2, n) - 1; i++)
  {
    m = n-1;
    for (j = 0; j < n; j++)
    {
      arr[m--] = (1&(i>>j)); 
    }
    W = 0;
    V = 0;
    for (k = 0; k < n; k++)
    {
      W += arr[k] * w[k];
      V += arr[k] * v[k];
    }
    if (W <= c)
    {
      if (V > MaxV)
      {
        MaxV = V;
        MaxW = W;
        count = 0;
        for (int h = 0; h < n; h++)
        {
          if (arr[h] == 1)
          {
            x[count++] = h+1;
          }
        }
      }
    }
  }
  for (i = 0; i < count; i++)
  {
    printf("%d ", x[i]);
  }
  printf("%d %d", MaxW, MaxV);
}

以上就是简单01背包问题的解决方法,如果大家有更简单更优的解法,欢迎大家在评论区讨论哦~

       写博客不易,希望大家多多关注和点赞,我会一直更新我的博客和大家一起进步的!

目录
相关文章
【动态规划刷题 1 】 第N个泰波那契数&& 三步问题
【动态规划刷题 1 】 第N个泰波那契数&& 三步问题
|
5月前
|
Java Go 图形学
一篇文章讲明白HDU4044GeoDefense(动态规划)
一篇文章讲明白HDU4044GeoDefense(动态规划)
20 0
|
5月前
|
存储 物联网
【洛谷 P1135】奇怪的电梯 题解(广度优先搜索)
这是一个关于奇怪电梯的编程问题摘要: - 电梯在每层停,且每层有特定数字 $K_i$ 决定上/下按钮的功能。 - 目标是从 $A$ 楼到 $B$ 楼,求最少按键次数,若无法到达则输出 `-1`。 - 输入包括 $N$(楼层数)、$A$(起点)和 $B$(终点),以及每层的 $K_i$ 数字。 - 使用广度优先搜索(BFS)解决,通过队列存储访问过的楼层,避免重复并计算步数。 - 当到达目标楼层时返回步数,队列空时返回 `-1`。
40 0
|
6月前
|
机器学习/深度学习
蓝桥杯-2/14天-完全平方数【另类思路】
蓝桥杯-2/14天-完全平方数【另类思路】
|
算法 C++
【每日算法Day 103】老题新做,几乎不会有人想到的解法,它来了
【每日算法Day 103】老题新做,几乎不会有人想到的解法,它来了
101 0
可能你已经刷了很多01背包的题,但是真的对01背包领悟透彻了吗?,看我这一篇,使君对01背包的理解更进一步【代码+图解+文字描述】
可能你已经刷了很多01背包的题,但是真的对01背包领悟透彻了吗?,看我这一篇,使君对01背包的理解更进一步【代码+图解+文字描述】
|
数据安全/隐私保护 Python
一眼就解密题解
一眼就解密题解
196 0
一眼就解密题解
|
算法
做题
学习编程语言的过程要记得刷题哦
177 0
做题
|
算法
算法理论——动态规划(一看就会)
动态规划算法的基本思想是:将带求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解中得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,避免重复求解。
112 0
点杀dp算法(动态规划)——LeetCode白手起家成股神
正片开始👀 概念👏 说到动态规划,什么是动态规划?
点杀dp算法(动态规划)——LeetCode白手起家成股神