一、问题描述

给定n种物品和一个背包。物品i的质量Wi,其价值Vi,背包的容量为c。问如何选择装入背包中的物品,使得装入背包中的物品总价值最大?

二、解题思想

01背包和最长公共子序列都是动态规划题目中求最优解的问题,不同在于,01背包问题,即使发现物品可以放入背包,但是在采取放或者不放的措施时,还要进行选择。(这就是保证最优解的条件)

我们先根据题意有如下假设:假设物品的种类和背包的容量是变化的,是逐渐增多的。我们每个不同容量的背包的最大价值,建立在先前背包最大价值的基础上。例如:背包容量为5的最优解,建立在背包容量为4的最优解的基础上。

既然容量和物品种类是变化的,那么我们建立一个二维数组(下文均称最佳价值表),横向代表背包容量,纵向代表物品种类,将每个不同容量的背包的最优解记录在最佳价值表里(这个最佳价值表记录的是满足题意的不同背包容量的最优解),如下图所示。由此正式开始思解题算法:思考递推式。

依照假设,就会得出如下情况:

A、当只有0种物品时,无论背包的容量是多少,背包内物品的总价值都为0(因为没有东西可放);当物品的种类很多时,但是背包的容量为0,背包内物品的总价值仍然为0(因为放不进去啊!)所以这个最佳价值表的第0行,第0列都是“0”,其中V[0][0]=0,不是因为我在程序中按照上述赋值为0,其真实原因是:只要是宏变量,声明在头文件下的变量,其初值都会自动为0。上述内容相当于对这个最佳价值表做了一个初始化,如下图所示:

B、当物品的种类和背包容量按照上图递增时,就会又出现一种情况:物品不能放入背包(因为物品的质量大于当前背包可容纳的质量)、物品能放入背包。

C、物品能放入背包也要分两种:物品要放入、物品不放入。那么可能你要提问了,为什么物品能装入但是却不选择装入呢?

因为我们这个二维数组存储的是背包的最佳价值表。这个物品虽然能放到背包内,但是如果它的体积过大,放入后势必会影响后续的物品放入,导致此最佳价值表违反了其“最佳”二字。如果第?个物品没有装入背包,则背包中物品价值就等于把前?−1个物品装入容量为?的背包中所取得的价值; 如果把第?个物品装入背包,则背包物品的价值等于第?−1个物品装入容量为?−weight[?]的背包中的价值加上第?个物品的价值value[?]。

综上:

A、V[i][0]=V[0][j]=0       //简单初始化

B、V[i][j]=V[i-1][j]          //物品不能放入

C、V[i][j]=max(v[i-1][j-weight[i]]+value[i],v[i-1][j])   //物品能放入

表达式详细解析:

看到这,有的读者就会有很多问题,我来以一问一答的形式让大家更加来了解这道题目的解题思想:

Q1:为什么表达式中每次用当前背包的总容量和新出现的物品的质量作比较,而不是用背包剩余的容量与新出现的物品的质量作比较?

A1:这个问题也是我接触动态规划问题之初提过的一个问题。01背包是典型的动态规划问题,既然是动态规划问题,那么就要动起来,整个问题中,动就只有一个——物品放入背包中。你可以设想一下,假设你在实际操作的时候,虽然给出的物品很多,但因为你目光有限,所以看到的东西也是一个一个进入眼帘。你可能会先将一个物品放入背包,但是因为后来出现了又小、价值又高的物品,你在权衡之后,可能又得把之前放入的这个物品掏出,腾出空间来放当前这个质量小、价值高的物品·······说了这么多铺垫,可能有的人已经明白了:这道题的关注点只在于背包能放得下还是放不下,而不是背包放进一些东西之后剩余的空间放的下还是放不下。这个其实直接可以从上述C的表达式可以看出,即:发现物品可放入的时候,你需要以背包的总价值作为衡量依据,到底是放入价值更高了(此时有的人可能会问了,难道物品放入背包后价值还会降低?因为放入物品的时候,需要腾出一定的空间,这就需要拿出背包里的物品,所以放入物品价值不一定更高)还是不放价值更高了,所以用一个max函数来比较。如果发现放入价值高,那就得腾出空间(用最佳价值表的纵轴坐标)

Q2:做这类问题的时候,有什么秘诀没有?

A2:1、既然是动态问题,那么我们的大脑就得灵活,而且得联系实际情况,把大问题化成简单的小问题。计算机是一个很傻的处理机器,重复做着相同的工作,唯一的优点就是快,我们需要做的事情就是告诉他应该做什么事情,做的次数等,其他的就不需要多想了。 2、第二点就是不要多想,直接推导递推式,然后求解,就像Q1的那种问题就不要多加考虑了。

三、具体实现

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int V[100][100];//用来存储背包的最大价值
int weight[100]; //存储物品的重量
int value[100];//存储物品的价值
int state[100];//存储物品的选取状态
int max(int a,int b)//比较价值大小函数
{if (a>=b)return a;else return b;
}
int KnapSack(int n,int weight[],int value[],int state[],int capacity)//动态规划求解函数
{int i,j;//循环变量//V[0][0] = 0;for (i=1;i<=n;i++)//当j=0时(j代表背包容量),0容量什么都装不进去,所以V[i][j]=0;V[i][0]=0;for (j=1;j<=capacity;j++)//当i=0时,代表没有物品,即使背包容量再大,其V[0][j]=0;V[0][j]=0;//#####下面进行判断######for (i=1;i<=n;i++)//i代表物品,j代表背包容量{//j代表背包的容量,将其从0逐步增加到输入的背包容量,相当于以背包的容量为限制,一步一步求得最大价值的方法。for (j=1;j<=capacity;j++){if(j<weight[i])//表示该物品?不能装入背包。V[i][j]=V[i-1][j];//表明此处的价值等于前i-1个物品装入的价值。else//第?个物品的重量小于背包的容量后就会有两种情况,一种放入,一种不放入,求这两种情况中Value最大的。V[i][j]=max(V[i-1][j],V[i-1][j-weight[i]]+value[i]);//如果把第?个物品装入背包,则背包物品的价值等于第?−1个物品装入容量位?−weight[?]的背包中的价值加上第?个物品的价值value[?]//如果第?个物品没有装入背包,则背包中物品价值就等于把前?−1个物品装入容量为?的背包中所取得的价值。}}j=capacity;//为标记“哪件物品放入背包”做准备for(i=n;i>=1;i--)//标记选出的物品函数{if(V[i][j]>V[i-1][j]){state[i]=1;//1表示选中j=j-weight[i];}elsestate[i]=0;//0表示未选中}printf("选中的物品是:");for(i=1;i<=n;i++)printf("%d ",state[i]);printf("\n");cout<<"V[i][j]中的数字是:\n";for(int i=0;i<=n;i++){for(int j=0; j<=capacity;j++){printf("%3d", V[i][j]);if (j == capacity){printf("\n");}}}return V[n][capacity];
}
int main()
{int s;//获得的最大价值int n = 0;//用于循环输入cout<< "请输入物品的个数:";cin >> n;cout << "请输入物品对应的质量:";for (int i = 1; i <= n; i++)cin >> weight[i];cout << "请输入物品对应的价值:";for (int i = 1; i <=n; i++)cin >> value[i];cout << "请输入背包最大容量:";int capacity;cin >> capacity;//背包最大容量s = KnapSack(n, weight, value, state, capacity);cout<<"最大物品价值为:"<<s<<endl;system("pause");return 0;
}

其中有一个for循环用来找出哪些东西被放入背包中,1代表放入,0代表没放入。

为了方便理解,我来多贴几张图,在这里就不做gif图了,大家顺着我的这个图去理解。

函数种前两个for循环程序执行之后:(蓝色区域为最佳价值表区域)

这个是只有物品1的时候:

出现物品2:其中绿色的6就是一个在比较之后填入的价值,绿色的9是当前两个物品的总和。

按照函数中的算法,一个一个模拟的把数字填写进去,相信你就会理解这道题目了。

C语言(CED)01背包——动态规划第二题相关推荐

  1. 01背包.动态规划.c语言实现

    二维dp数组01背包 确定dp数组以及下标的含义 使用二维数组,即dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少       2.递推公式:dp[i][ ...

  2. 【nyoj - 860】 又见0-1背包 (dp,反向0-1背包,好题好思路)

    题干: 又见01背包 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 输入 多组测试数据. 每组测试数据第一行输入,n 和 W ,接下来有n行,每行输入两个数,代表第i个物品的 ...

  3. 1038 01背包动态规划

    #1038 : 01背包 #include <iostream> #include <stdio.h> #include <algorithm>using name ...

  4. LeetCode 474. 一和零(01背包动态规划)

    1. 题目 在计算机界中,我们总是追求用有限的资源获取最大的收益. 现在,假设你分别支配着 m 个 0 和 n 个 1.另外,还有一个仅包含 0 和 1 字符串的数组. 你的任务是使用给定的 m 个 ...

  5. POJ1417 True Liars ——种类并查集+01背包+路径** 好题

    ​​​​​​POJ1417 题意: 有n行输入形如x, y, str,str为yes表示x说y是天使,str为no表示x说y不是天使(x, y为天使,恶魔的编号,1<=x,y<=p+q): ...

  6. 0-1背包动态规划c语言,动态规划解决0-1背包问题程序看不懂,请大家看看帮忙解决下...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 c-=w[i]; } } if(m[n][c] >0) flag[n] = 1; else flag[n] = 0; } /* 打印最优解*/ vo ...

  7. C语言:01背包算法

    一.实验目的 1.熟悉C/C++语言的集成开发环境: 1.通过动态规划算法的示例程序理解动态规划算法的基本思想 2.运用动态规划算法解决实际问题加深对动态规划算法的理解和运用 二.实验内容 1.动态规 ...

  8. BFU C.yi的书包 01背包【水题】

    先上题 描述 终于到了开开心心的暑假,然而对于一名ACMer来说,暑假并没有那么轻松.fudq跟我说:"我们ACMer修的,是一份境界.外修语法,内修算法.以数据为根,算天算地算自己.我这有 ...

  9. 动态规划之背包问题——01背包

    算法相关数据结构总结: 序号 数据结构 文章 1 动态规划 动态规划之背包问题--01背包 动态规划之背包问题--完全背包 动态规划之打家劫舍系列问题 动态规划之股票买卖系列问题 动态规划之子序列问题 ...

最新文章

  1. UVa11022 String Factoring(kmp+dp)
  2. ASSERT(IsOpen());
  3. 0603贴片电阻阻值对照表_怎样读贴片电阻阻值
  4. jzoj3913-艰难的选择【差分,统计】
  5. 初识python多线程
  6. C# 设计模式 - 单例模式 演示
  7. python语言的单行注释以井号开头_【学习】Python语言入门
  8. 4.maven中常用的构建命令
  9. 在已有的服务器上如何部署网站,如何在云服务器上部署网站
  10. 三星 S7562i 一键 Root
  11. 别催了,医药行业数字化转型真的“急不得”
  12. Python xlwt 操作 excel 表格基础(三):单元格格式、字体格式、对齐方式、边框及填充等
  13. html文件无法通过复制粘贴传输,电脑不能复制粘贴的三种解决办法
  14. 关于TopoJSON以及制作方法
  15. U盘中病毒,文件消失,但U盘的大小却没有改变
  16. Chrome浏览器添加信任站点
  17. Angular4 - http
  18. ai跟随路径_Illustrator描边路径 AI指定数量沿全路径混合小技巧 AI制版文字变粗...
  19. MySQL8.0.27版本于2021年10月19日正式GA和新功能介绍
  20. 对话李志飞:出门问问最早将于2019年底考虑上市

热门文章

  1. python连等号_Python比较2列表和2元组用等号
  2. 查看python版本命令
  3. JAVA将ResultSet结果集遍历到List中
  4. PMP考试技巧(必备)
  5. SpringMVC 集成 mybatisPlus
  6. git.exe init#timeout = 10错误:克隆远程repo'origin'时出错hudson.plugins.git
  7. java12/6作业1
  8. gbase 8s oracle,GBase8s 查看数据库表空间信息
  9. java管理员登录_idea实现管理员登录javaweb
  10. C语言 全局变量和局部变量区别 - C语言零基础入门教程