【0-1背包问题】“动态规划”——《算法设计与分析(第五版)》
文章目录
- 一、算法要求
- 1. 思路
- 2. 示例
- 二、完整代码
- 1. 主文件
- 2. 头文件
- 3. 效果展示
- 三、补充
一、算法要求
给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?
1. 思路
有n种可选物品1,…,n ,放入容量为c的背包内,使装入的物品具有最大效益。
n :物品个数
c :背包容量
p1,p2, …, pn:个体物品效益值
w1,w2, …,wn:个体物品容量
0-1背包问题的解法:物品1,…,n的一种放法(x1, ···,xn的0/1赋值),使得效益值最大。
假定背包容量不足以装入所有物品:面临选择
优化原理:无论优化解是否放物品1,优化解对物品2,…,n的放法,相对剩余背包容量,也是优化解。
2. 示例
假设:n=5,c=10p=[6,3,5,4,6]w=[2,2,6,5,4]
(1,1,0,0,1)为其优化解,即放物品1,2,5 。物品1占背包容量2,剩下容量为8。
考虑子问题:n=4,c=8,物品为2,3,4,5
(1,0,0,1),即放物品2和5,是子问题的优化解,背包问题满足优化原理。
二、完整代码
1. 主文件
main.cpp:
#include"Improve1.h"int main(){//初始化控制台Console();//核心算法CoreAlgorithm();// 输出cout << "\nThe maximum total value of the items in the backpack is:" << m[1][capacityPack] << endl;cout << "The selected item situation is:";for (int i = 1; i <= numItem; i++)cout << x[i] << " ";cout << endl;return 0;
}
2. 头文件
Improve1.h:
#pragma once#ifndef __IMPROVE1__
#define __IMPROVE1__#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
using namespace std;/*n :物品个数*c :背包容量*p1,p2, …, pn:个体物品效益值*w1,w2, …,wn:个体物品容量*/int numItem = 5,capacityPack = 10;
int weightItem[] = { 0, 2, 2, 6, 5, 4 }, //从第一序列开始valueItem[] = { 0, 6, 3, 5, 4, 6 };
int* x; // 物品是否被放入背包
int** m; // 最大价值// 用户输入
void Console() {cout << "The following are the default items’ quantity, value and weight and backpack capacity: \n"<< "\n#Number of items: " << numItem<< "\n#Number of backpacks: " << capacityPack;cout << "\n#Corresponding weight: ";for (int i = 1; i < numItem + 1; i++)cout << setw(3) << weightItem[i];cout << "\n#Corresponding value: ";for (int i = 1; i < numItem + 1; i++)cout << setw(3) << valueItem[i];x = new int[numItem + 1];m = new int* [numItem + 1];for (int i = 0; i <= numItem; i++) {m[i] = new int[capacityPack + 1];memset(m[i], 0, sizeof(int) * (capacityPack + 1)); // 将表m所有元素设为0}cout << endl;}//核心算法
void CoreAlgorithm(){//Knapsack最大价值表int jMax = min(weightItem[numItem] - 1, capacityPack); // 避免存在单个重量超出背包容量的物品使数组m越界for (int j = 0; j <= jMax; j++) // 以下两个for循环是最大价值表m的最后一行m[numItem][j] = 0;for (int j = weightItem[numItem]; j <= capacityPack; j++)m[numItem][j] = valueItem[numItem];for (int i = numItem - 1; i > 1; i--) { // 以下是表m最后一行以上的部分jMax = min(weightItem[i] - 1, capacityPack);for (int j = 0; j <= jMax; j++)// 背包容量<物品重量,即装不下;将m[i+1][j](下一行同列)的值赋给m[i][j]m[i][j] = m[i + 1][j];for (int j = weightItem[i]; j <= capacityPack; j++)// 背包容量>=物品重量,即可以装下;// 放:m[i][j]=m[i + 1][j - w[i]] + v[i]// 不放:m[i][j]=m[i + 1][j]// 哪个价值大,就采取哪种方式m[i][j] = max(m[i + 1][j], m[i + 1][j - weightItem[i]] + valueItem[i]);}m[1][capacityPack] = m[2][capacityPack];if (capacityPack >= weightItem[1])m[1][capacityPack] = max(m[1][capacityPack], m[2][capacityPack - weightItem[1]] + valueItem[1]);//Traceback将最优解存入数组int cTemp = capacityPack; // 临时背包容量for (int i = 1; i < numItem; i++) {if (m[i][cTemp] == m[i + 1][cTemp])x[i] = 0; // 价值相等,说明没有放入这个物品,0else {x[i] = 1; // 价值不相等,说明放入了这个物品,1cTemp -= weightItem[i]; // 放入了一个物品,背包剩余容量为原容量-物品重量}}x[numItem] = (m[numItem][capacityPack]) ? 1 : 0; // 最后一个物品,非0为true放入,0为false不放入
}#endif
3. 效果展示
三、补充
优化值间的递归式:
虽然不知道优化解是否放物品1,但从优化原理能建立优化值间的递归式:
设f(i, y)为以背包容量y,放物品i,…,n,得到的优化效益值,以下递归关系成立:
f(1,c)=max{f(2,c), f(2,c-w1)+p1} 不放物品1、放物品1
先求子问题的优化值(递归),再从2种可能性中求出最优的。
须对任意给定容量y,任意i,…,n 种物品求解子问题。
举例:
n=3, c=116
w=[100,14,10]
p=[20,18,15]
放进物品1(x1 = 1),背包容量还剩r=16, [x2,x3]= [1,0] 为子问题的优化解,值为18,总效益值为20+18=38
不放物品1(x1= 0)则对于剩下的两种物品而言,容量限制条件为116,[1,1]为子问题优化解,值为33。
前者效益值为38,后者为33;
所以优化解为[1,1,0], 优化值为max{38,33}=38。
- 算法复杂度分析:
(1)时间复杂度:算法中有主要的是两层嵌套的for循环,其时间复杂度为O(n×w)。
(2)空间复杂度:由于二维数组c[n][w],所以空间复杂度为O(n×w)。 - 算法优化拓展:
首先有一个主循环i=1,2,…,N,每次算出来二维数组c[i][0~w]的所有值。那么,如果只用一个数组 dp[0~w],能不能保证第i次循环结束后dp[i]中表示的就是我们定义的状态 c[i][j]呢?
c[i]]由c[i-1][i]和c[i-1] [j-w[i]]两个子问题递推而来,能否保证在递推 c[i][i]时(也即在第i次主循环中递推 dp[j]时)能够得到c[i-1][j]和c[i-1][j-w[i]]的值呢﹖事实上,这要求在每次主循环中以j=w,w-1,…,1,0的顺序倒推dp[j],这样才能保证递推 dp[j]时dp[j-c[i]]保存的是状态c[i-1][j-w[i]]的值。
伪代码如下:
for i=1..nfor j=w..0dp [j]=max{dp[j] ,dp [j-w[i]]+v[i]};
其中,dp[j]=max {dp[j],dp[j-w[i]]}就相当于转移方程c[i][j]-max {c[i-1][j],c[i-1][j-w[i]]},
因为这里的dp[j-w[i]] 就相当于原来的c[i-1][j-w[i]]。
文档供本人学习笔记使用,仅供参考。
【0-1背包问题】“动态规划”——《算法设计与分析(第五版)》相关推荐
- 计算机算法设计与分析第五章思维导图知识点总结 ( 初稿 )
复习链接 计算机算法设计与分析第一章思维导图 计算机算法设计与分析第二章思维导图&&知识点总结 计算机算法设计与分析第三章思维导图&&知识点总结 计算机算法设计与分析第 ...
- PHP第五周答案,算法设计与分析第五周作业——Word Ladder
算法设计与分析第五周作业--Word Ladder 上周找了一道深度搜索优先搜索的算法题来做,于是这周就选了一道广度优先搜索算法题来试试手. 本周所选题目:原题目链接 题目详情 题目大意:给出一个字符 ...
- 计算机算法设计与分析第四版复习,计算机算法设计与分析(第4版)第1章.ppt
<计算机算法设计与分析(第4版)第1章.ppt>由会员分享,可在线阅读,更多相关<计算机算法设计与分析(第4版)第1章.ppt(50页珍藏版)>请在人人文库网上搜索. 1.计算 ...
- 计算几何学习总结(使用教材算法设计与分析(第二版))
** 计算几何总结(使用教材算法设计与分析(第二版)李春葆 清华大学出版社) ** (代码大部分为书中原有代码,如有雷同,实属正常.) #include<bits/stdc++.h> us ...
- SDU 2021.1 算法设计与分析考试 回忆版
SDU 2021.1 计科 算法设计与分析考试 计算题 DFSDFSDFS:画出深度优先树:给出每个点的开始时间和结束时间:给出每条边的分类 有向图上的多源最短路径,要求计算distancematri ...
- [XJTUSE 算法设计与分析] 第五章 回溯法
第五章 回溯法 填空题会有代码填空,大题会手动回溯 学习要点 理解回溯法的深度优先搜索策略. 掌握用回溯法解题的算法框架 (1)递归回溯 (2)迭代回溯 (3)子集树算法框架 (4)排列树算法框架 5 ...
- 算法设计与分析 实验五 算法综合实验
实验5.<算法综合实验> 一.实验目的 理解和复习所学各种算法的概念 掌握和复习所学各种算法的基本要素 掌握各种算法的优点和区别 通过应用范例掌握选择最佳算法的设计技巧与策略 二.实验内 ...
- educoder算法设计与分析 实验五回溯法
实验五 回溯法 第1关:排列 第2关:子集合 第3关:TSP问题 第4关:n皇后问题 第5关:0-1背包 第1关:排列 题目描述: 1.设计算法从前m个大写字母(m≤26)种取出n个字母的所有排列(组 ...
- 算法设计与分析第2版第一章
8.一个字符串采用String对象存储,设计一个算法判断该字符串是否为回文. package a; public class Test01 { public static void main(Stri ...
- 【Algorithm】算法设计与分析(第二版)- 王红梅 - JAVA / C++实现:3.9 荷兰国旗问题
题目 : 荷兰国旗问题.要求重新排列一个由字符R,W,B(R代表红色,W代表白色,B代表兰色,这都是荷兰国旗的颜色)构成的数组,使得所有的R都排在最前面,W排在其次B排在最后.为荷兰国旗问题设计一个算 ...
最新文章
- 新发现为类脑计算机开辟了道路
- android中string.xml使用总结,string.xml 的作用以及意义——国际化应用
- 产品经理有哪些类型?
- oracle_Grid Infrastructure 启动的五大问题
- IdentityServer4支持的授权类型以及组合
- 十九、Oracle学习笔记:行变量
- Atitit org.eclipse.jdt 的ast 架构 Eclipse JDT API spec
- python登陆linkedin过程分析,及二次验证(一)
- hashmap java 排序_Java HashMap 默认排序
- c语言智能车跑道检测程序,基于金属检测的智能循迹小车设计
- APP色彩搭配方案是由主色、辅助色和点缀色构成
- SCIgen与野鸡期刊的梗
- 华为手机鸿蒙系统测评,华为发布的鸿蒙系统到底有多牛(让理想成为现实)
- [Java基础]-- Jsp 介绍
- 同轴电缆抗干扰措施(二)
- 笔记本喇叭无声音解决方案
- java dozer,MapStruct相当于提示(Dozer)?
- 如何制作一个可以自动更新的Github个人主页
- SpringBoot2.0整合Redis实战
- 清华大学计算机系刘斌,清华大学计算机科学与技术系导师简介:林闯