背包问题

动态规划——背包问题

倖福魔咒の 提交于 2020-02-28 15:17:10
在写博客之前,先列出两个背包九讲链接以供参考 yxc在B站上讲的背包九讲: 背包九讲专题 以及一篇非常经典的 dd大牛的《背包九讲》 0 1背包问题 完全背包问题 多重背包问题 分组背包问题 0 1背包问题 有N件物品和一个容量为V的背包。第i件物品的费用是c[i](本题里是v[i]),价值是w[i]。 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 在求状态转移方程的方面,思路是集合划分: f(i,j):“在i个东西里面选质量为j的东西的总商品价值”这一集合可分为“选的所有东西里面 不包含i ”和“选的东西里面 包含i ”两种情况。 的话 不含i的情况即是f(i-1,j)【在i-1个东西中选质量为j的东西】 含i的情况即是f(i-1,j-V i )+w i 【由于选了i,那就是在i-1个东西中选j-V i 质量的总价值加上i的价值】 将上述两个集合取价值最大的取法,即为“在i个东西里面选质量为j的东西的总商品价值” 优化1:减少操作次数 由于上述的情况中,含i的情况是不一定存在的(那是当背包最大重量j<V i 即装不下的时候不需要考虑) 优化2:将二维数组优化为滚动数组 滚动数组:如果f(i)的计算仅仅只用了f(i-1)来完成计算的话,就只需要开一个f[2][N]的数组即可(可以运用e=1-e来实现滚动) 值得注意的是

DP-01背包问题

微笑、不失礼 提交于 2020-02-28 12:37:46
思路:dp[i][j]表示的是前i个物品背包所能容纳不超过bagw的最大价值. #include<iostream> using namespace std; const int maxn = 100; int main() { int n,bagw; int w[maxn],v[maxn]; int dp[maxn][maxn]; cin>>n; for(int i = 0; i < n; i++) { cin>>w[i]>>v[i]; } cin>>bagw; for(int i = 0; i < n; i++) //初始化第一列(背包重为0时的最大价值) dp[i][0] = 0; for(int j = 0; j <= bagw; j++) //初始化第一行 { if(j >= w[0]) dp[0][j] = v[0]; else dp[0][j] = 0; } for(int i = 1; i < n; i++) { for(int j = 1; j <= bagw; j++) { if(j >= w[i]) { dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + v[i]); //选与不选取最大值 } else { dp[i][j] = dp[i - 1][j]; } } } cout<<dp[n-1][bagw]<

DP-01背包问题

别来无恙 提交于 2020-02-28 12:33:48
思路:dp[i][j]表示的是前i个物品背包所能容纳不超过bagw的最大价值. #include<iostream> using namespace std; const int maxn = 100; int main() { int n,bagw; int w[maxn],v[maxn]; int dp[maxn][maxn]; cin>>n; for(int i = 0; i < n; i++) { cin>>w[i]>>v[i]; } cin>>bagw; for(int i = 0; i < n; i++) //初始化第一列(背包重为0时的最大价值) dp[i][0] = 0; for(int j = 0; j <= bagw; j++) //初始化第一行 { if(j >= w[0]) dp[0][j] = v[0]; else dp[0][j] = 0; } for(int i = 1; i < n; i++) { for(int j = 1; j <= bagw; j++) { if(j >= w[i]) { dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + v[i]); //选与不选取最大值 } else { dp[i][j] = dp[i - 1][j]; } } } cout<<dp[n-1][bagw]<

多重背包问题的二进制优化

我们两清 提交于 2020-02-28 05:08:01
前情提要: 动态规划——背包九讲——多重背包问题 多重背包问题 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。 这题目和完全背包问题很类似,特点是:每种物品都有自己特异的件数、花费、价值。 朴素算法: 每种物品有n[i]件可以取用,需要枚举每种物品选了多少件(枚举件数不能超过背包容量) for ( int i = 1 ; i <= n ; i ++ ) for ( int j = 0 ; j <= m ; j ++ ) for ( int k = 0 ; k <= s [ i ] && k * v [ i ] <= j ; k ++ ) //与完全背包相比仅仅是加了一个判断条件而已 f [ i ] [ j ] = max ( f [ i ] [ j ] , f [ i - 1 ] [ j - v [ i ] * k ] + w [ i ] * k ) ; 朴素算法的时间效率很低,通过下面的二进制优化可以把遍历每种物品的n[i]件物品的时间复杂度从O(n)优化为O(log n) 优化:通过展开化简式子不可行,换用二进制优化方式 正篇:背包问题的经典二进制优化 第i种物品是有n[i]件的,这个n[i]可以被展开为n[i]=2 0 +2 1 +…+2 k +c (其中2 k+1 < n[i] < 2 k+2 ) (2 0 +2 1 +

多重背包问题

谁都会走 提交于 2020-02-27 06:56:10
Problem Description 为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。 Input 输入第一行为T,表示数据组数,对于每组数据的第一行二个数n(n<=500),m(m<=6000),其中n代表希望购买的奖品的种数,m表示拨款金额。 接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和购买的数量(买0件到s件均可),其中v<=100,w<=1000,s<=10。 Output 对于每组数据输出一个数,表示此次购买能获得的最大的价值(注意!不是价格)。 Sample Input 1 5 1000 80 20 4 40 50 9 30 50 7 40 30 6 20 20 1 Sample Output 1040【解析】和01差不多 区别在于 每个物品的数量是有限的(或者说是给定的) 每一种物品假设有n[i]件,那么这个物品的决策就是n[i]+1(为什么要加1呢,因为还可以不取这件物品,也算一种决策方式)下面的代码是两种方法 第二种为 二进制优化 理解一下【代码】和01很像,只是1件物品改成的有限件 只需要加一个循环 枚举到底选几件好了 #include<iostream> #include<cstdio> using

背包入门

大城市里の小女人 提交于 2020-02-27 03:02:11
layout: post title: 背包入门 categories: [背包, 模板题] description: 背包入门 keywords: 背包, 模板 --- 背包 01背包 给定 \(N\) 个物品和容量是 \(V\) 的背包,以及N个物体的 \(v_i\) 和 \(w_i\) ,每个物体只有一件。 挑选一些物体,使得总体积小于等于V,目标是使得总价值最大,问最大价值是多少? 模板: 01背包 朴素写法 //#define judge // Author: oceanlvr #include <bits/stdc++.h> using namespace std; int n, V; const int maxn = 1e3 + 10; int v[maxn]; int w[maxn]; int f[maxn][maxn]; int main() { cin >> n >> V; for (int i = 1; i <= n; i++) { cin >> v[i] >> w[i]; } for (int i = 1; i <= n; i++) { for (int j = V; j <= 0; j--) { f[i][j] = f[i - 1][j]; if (j >= v[i]) f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i

0-1背包问题

╄→尐↘猪︶ㄣ 提交于 2020-02-25 00:52:07
1.定义   有一个容量为 N 的背包,要用这个背包装下物品使得价值最大,这些物品有两个属性:体积 w 和价值 v。   定义一个二维数组 dp 存储最大价值,其中 dp[i][j] 表示前 i 件物品体积不超过 j 的情况下能达到的最大价值。设第 i 件物品体积为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论: (1)第 i 件物品没添加到背包,总体积不超过 j 的前 i 件物品的最大价值就是总体积不超过 j 的前 i-1 件物品的最大价值,dp[i][j] = dp[i-1][j]。 (2)第 i 件物品添加到背包中,dp[i][j] = dp[i-1][j-w] + v。   第 i 件物品可添加也可以不添加,取决于哪种情况下最大价值更大。因此,0-1 背包的状态转移方程为: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w ] + v ) dp[i][j] = max(dp[i-1][j],dp[i-1][j-w]+v) d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w ] + v ) // W 为背包总体积 // N 为物品数量 // weights 数组存储 N

数据结构——背包问题

折月煮酒 提交于 2020-02-23 14:22:26
引言 算法的经典问题之一 背包问题 ,背包问题是动态规划(运筹学)的一个典型的例子,它的问题描述即规定背包所能容纳的最大重量,然后此时有一批物品对应不同的质量和价值,那么如何放置物品进入背包使得背包中的价值最大。 通常情况下,背包问题会分为两种情形: 物品可以切开放置到背包中,即物品的重量和价值可以按分数的形式放置 物品只能以整数的形式放置 前一种情况,只能用贪心算法解决去解决问题。后一种情况,则需要通过动态规划。 背包问题(整数) 首先,我们先来认识一下动态规划解决问题的步骤: 定义子问题 实现要反复执行来解决子问题的部分 识别并求解出基线条件 然后假设此时我们有一个这样的背包问题: 此时有一个背包可容纳的重量为 7,分别有重量为 2、3、4 对应价值为 3、4、5 的三个物品 ,并分别命名为物品 1、物品 2、物品 3。要如何往背包中放置物品,才能使得背包中的价值最高? 对于从事编程的同学而言,遇到略显复杂的问题,我们应该先建立数学模型。而对于这个背包问题,它的数学模型是这样的: 背包所能容纳的重量 w: 5 物品 重量 价值 1 2 3 2 3 4 3 4 5 ( 矩阵的行数为物品数量 + 1 ,列为背包所能容纳重量 + 1 ,初始化默认 0 列 0 行为 0 ) 第一阶段 i / w 0 1 2 3 4 5 0 0 0 0 0 0 0 1 0 0 3 3 3 3 2 0 3

背包问题2

纵饮孤独 提交于 2020-02-22 04:54:46
1268:【例9.12】 完全背包问题 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 10068 通过数: 5384 【题目描述】 设有nn种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为MM,今从nn种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于MM,而价值的和为最大。 【输入】 第一行:两个整数,MM(背包容量,M≤200M≤200)和NN(物品数量,N≤30N≤30); 第2…N+12…N+1行:每行二个整数Wi,CiWi,Ci,表示每个物品的重量和价值。 【输出】 仅一行,一个数,表示最大总价值。 【输入样例】 10 4 2 1 3 3 4 5 7 9【输出样例】 max=12 与01背包问题不同的是可以用无限次 将第二次遍历正序遍历的好处是可以将之前的结果累积起来,已达到多次使用的效果 即 当一个数是之前的一个数的两倍时他所累积的结果也是之前的两倍。 # include <iostream> using namespace std ; int f [ 35 ] [ 305 ] ; int main ( ) { int m , n ; cin >> m >> n ; int w [ 35 ] , c [ 35 ] ; for ( int i = 1 ; i <= n ; i ++ ) {

背包问题

喜你入骨 提交于 2020-02-18 07:36:00
一.01背包 有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。 f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。 状态转移方程: f[i][v]=max{ f[i-1][v] , f[i-1][v-c[i]]+w[i] } 将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为j的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。 # include <bits/stdc++.h> using namespace std ; int dp [ 1005 ] [ 1005 ] ; int weight [ 1005 ] ; int value [ 1005 ] ; int main ( ) { int n , m ; cin >> m >> n ; memset ( dp , 0 , sizeof ( dp ) ) ; //数组清空,其实同时就把边界给做了清理 for ( int i =