背包问题

第九讲 背包问题问法的变化

匿名 (未验证) 提交于 2019-12-03 00:03:02
以上涉及的各种背包问题都是要求在背包容量(费用)的限制下求可以取到的最大价值,但背包问题还有很多种灵活的问法,在这里值得提一下。但是我认为,只要深入理解了求背包问题最大价值的方法,即使问法变化了,也是不难想出算法的。 例如,求解最多可以放多少件物品或者最多可以装满多少背包的空间。这都可以根据具体问题利用前面的方程求出所有状态的值(f数组)之后得到。 还有,如果要求的是“总价值最小”“总件数最小”,只需简单的将上面的状态转移方程中的max改成min即可。 下面说一些变化更大的问法。 输出方案 一般而言,背包问题是要求一个最优值,如果要求输出这个最优值的方案,可以参照一般动态规划问题输出方案的方法:记录下每个状态的最优值是由状态转移方程的哪一项推出来的,换句话说,记录下它是由哪一个策略推出来的。便可根据这条策略找到上一个状态,从上一个状态接着向前推即可。 还是以01背包为例,方程为 f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} 。再用一个数组g[i][v],设g[i][v]=0表示推出f[i][v]的值时是采用了方程的前一项(也即f[i][v]=f[i-1][v]),g[i][v]表示采用了方程的后一项。注意这两项分别表示了两种策略:未选第i个物品及选了第i个物品。那么输出方案的伪代码可以这样写(设最终状态为f[N][V]): 另外

背包详解

匿名 (未验证) 提交于 2019-12-02 23:56:01
01背包 题目 有N件物品和一个容量为V的背包,每种物品只有一个,放入第i件物品的费用是C i ,价值是W i 。 求将若干个物品装入背包得到的最大价值。(总费用不能超过总容量V) 解析 最基本的背包,每种物品只有一个,可放可不放。 很容易可以定义出状态F[i][j]表示前i件物品放入一个容量为j的背包的最大价值。 状态转移方程是F[i][j]=max(F[i-1][j],F[i-1][v-C i ]+W i )(即不放与放)。 所以可以得到代码: //F数组初值为0 for(int i=1;i<=N;i++) { for(int j=0;j<C[i];j++) F[i][j]=F[i-1][j]; for(int j=C[i];j<=V;j++) F[i][j]=max(F[i-1][j],F[i-1][j-C[i]]+W[i]); } 很显然时间复杂度已将无法优化了,考虑优化空间复杂度。 第二维显然无法舍去,考虑舍去第一维。 定义状态F[j]表示原来的F[i][j],舍去的i将在循环中体现。 F[i][j]是由F[i-1][j]与F[i-1][j-C i ]推导出的,所以我们需要保证F[j]也是由它们推导而出。 事实上,如果我们逆着做j循环,即j从V到0循环,计算F[j]时,F[j-C i ]的值就是F[i-1][j-C i ]的值。 所以我们可以将其优化成一维数组。

回溯算法――0-1背包

匿名 (未验证) 提交于 2019-12-02 23:55:01
回溯算法的思想:每到一个十字路口A,就选择一条路走a,如果a走不通,则回到十字路口A,选择其他bcd之一,进行走。若依然走不通,则退回到A之前的十字路口,重复上面的操作。 利用回溯算法解决的经典问题:数独、八皇后、0-1背包、图的着色、旅行商问题、全排列等等。 0-1背包问题 #include <iostream> #define MAX_WEIGHT 100 using namespace std ; // arr 待装包的物品重量, // curweight 当前i物品的重量 // i 当前即将放入的i物品 // num 可用物品的数量 // bagweight 当前背包的总重量 void fill ( int * arr , int curweight , int i , int num , int & bagweight ) { if ( curweight == MAX_WEIGHT || i == num ) // 装满,或者考察完所有物品 { if ( curweight > bagweight ) { bagweight = curweight ; // 记录历史最大装载量 // cout << bagweight << "***" << endl << endl; } return ; } fill ( arr , curweight , i + 1 , num

#(抽象背包的转化)洛谷P1282 多米诺骨牌(提高+/省选-)

匿名 (未验证) 提交于 2019-12-02 23:55:01
题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点。现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|。例如在图8-1中,S1=6+1+1+1=9,S2=1+5+3+2=11,|S1-S2|=2。每个多米诺骨牌可以旋转180°,使得上下两个方块互换位置。 编程用最少的旋转次数使多米诺骨牌上下2行点数之差达到最小。 对于图中的例子,只要将最后一个多米诺骨牌旋转180°,可使上下2行点数之差为0。 输入格式 输入文件的第一行是一个正整数n(1≤n≤1000),表示多米诺骨牌数。接下来的n行表示n个多米诺骨牌的点数。每行有两个用空格隔开的正整数,表示多米诺骨牌上下方块中的点数a和b,且1≤a,b≤6。 输出格式 输出文件仅一行,包含一个整数。表示求得的最小旋转次数。 输入输出样例 输入 #1 复制 4 6 1 1 5 1 3 1 2 输出 #1 复制 1 QAQ 那么我们如何调整呢?我们先把骨牌反转,使点数大的在上方;这样保证上方的点数和一定大于下方的点数和;那么翻转时的点数改变就是上下点数的差值乘以 2 了!想到这里,我们可以考虑到:一开始的上下的点数的差值抽象成背包的体积,每一个骨牌当成一个物品,因为我们一开始就把点数大的放在了上面,而每放一次,翻转次数就+ 1 。考虑:要是我后来后悔了,我发现不翻这个骨牌更好怎么办

8.18 二讲背包问题之完全背包

匿名 (未验证) 提交于 2019-12-02 23:55:01
  今天为大家讲解完全背包问题。   完全背包和01背包的区别便在于完全背包可以无限选取商品,而01背包只可以选取一个,从一维数组的角度来想,01背包从后往前枚举(m到w[i])可以保证每次j空间时只选取该商品选取了一次,避免了重复;而完全背包从前往后枚举(w[i]到m)会把小于m的2*w[i],3*w[i]...k*w[i]都加进来. 为大家放一道例题 题目描述 设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。 输入 输出 仅一行,一个数,表示最大总价值。 样例输入 10 4 2 1 3 3 4 5 7 9 样例输出 max=12题解代码: #include<iostream> using namespace std; int m,n,dp[205],w[35],c[35]; int main(){ } 来源: https://www.cnblogs.com/cxs070998/p/11371089.html

用二维和一维数组解决0-1背包问题

淺唱寂寞╮ 提交于 2019-12-02 23:52:30
问题描述 0/1背包问题    物品集合U={u1,u2…un},体积分别为s1,s2…..sn,价值分别为v1,v2….vn;容量C的背包。设计算法实现放入背包的物品价值最大。 输入描述   第一行输入物品数n和背包的容量C,接下来n行分别输入每个物品体积及价值 输出描述   输出最大价值数 输入样例   3 10   3 4   4 5   5 6 输出样例   11 问题分析 每个物品有装入和不装入两个选择,定义n维向量x=(x 1 ,x 2 ,x 3 ,~~x n ),其中x k =1表示物品k装入,x k =0表示不装入,因此一个0-1向量代表了一种装载方案, 现在要求给出一种最优装载方案x,满足总容量<=C,使得总价值最大,那么考虑 前i个物品 1,2,3~~i,以及背包容量j, 记D[i][j]为 前i个物品在背包容量为j的情况下所能得到的最大价值 。 它满足以下递推关系: (1) D[0][j]=0,j=0,1,2,,C; 物品为0时肯定最大价值全为0 这是递推起点 需要初始化 (2) 若j<w[i],D[i][j]=D[i-1][j],否则D[i][j]=max(D[i-1][j],D[i-1][j-w[i]]+v[i]); 这是递推表达式 D[i][j]的计算要用到上一行的两个元素,因此计算顺序和填二维数组的顺序是一样的,从左往右,再从左往右 则最后右下角的D

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

匿名 (未验证) 提交于 2019-12-02 23:52:01
算法:二进制优化,动态规划 #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N=2010; int v[N],w[N],cnt; int f[N]; int main(void){ int n, m; cin>>n>>m; for(int i=1,a,b,s;i<=n;i++){ cin>>a>>b>>s; int k=1; while(k<=s){ cnt++; v[cnt]=a*k; w[cnt]=b*k; s-=k; k*=2; } if(s>0){ cnt++; v[cnt]=a*s; w[cnt]=b*s; } } n=cnt; for(int i=1;i<=n;i++){ for(int j=m;j>=v[i];j--){ f[j]=max(f[j],f[j-v[i]]+w[i]); } } cout<<f[m]<<endl; return 0; }

求方案数(背包问题)

匿名 (未验证) 提交于 2019-12-02 23:43:01
输入格式 第一行是两个数字,表示 N 和 M 。 第二行是 N 个数。 1 ≤ N ≤ 100, 1 ≤ M ≤ 10 5 , 1 ≤ Ai ≤ 1000 . 输出格式 一个数字,表示和为 M 的组合的个数。 样例 样例输入 4 4 1 1 2 2 样例输出 3 题解: 该题类似01背包 , 将N个数字 放入容量为 M 的容器中 , 有多少种方法? 初始条件dp[0] = 1; 其他都为0; 状态转移方程已经考察了所有可能的背包组成方案 比如 dp[2] = 2 表示有俩种可以组成2的方案 , 那么dp[4] = a[i] + 2 的话就可以直接加上dp[2] 的方案数了; 代码: #include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 8; int dp[maxn] , a[maxn]; int main() { int n , m; scanf("%d %d" , &n , &m); for(int i = 1 ; i <= n ; i++) { scanf("%d" , &a[i]); } memset(dp , 0 , sizeof(dp)); dp[0] = 1; for(int i = 1 ; i <= n ; i++) { for(int j = m ; j >= a[i] ; j--)

动态规划之背包问题(一)

匿名 (未验证) 提交于 2019-12-02 23:43:01
背包问题 动态规划之背包问题(一) 问题介绍 直观思维 普通递归 记忆搜索式递归 穷竭搜索式递归 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一个表格 设定内容居中、居左、居右 SmartyPants 创建一个自定义列表 如何创建一个注脚 注释也是必不可少的 KaTeX数学公式 新的甘特图功能,丰富你的文章 UML 图表 FLowchart流程图 导出与导入 导出 导入 动态规划之背包问题(一) 背包问题是动态规划最经典的问题之一,这篇博客会初步探索背包问题,在后续系列会继续深入。 问题介绍 有n个物品,价值和重量分别为vi和wi,背包承重W,求装入背包的最大价值。 例子: n=4 w={2,1,3,2} v={2,2,4,3} W=5 输出 V=7(选择第0,1,3件物品或者第2,3件物品) 直观思维 在背包还放得下这件物品时,选与不选都试一下,选二者的较大值 在背包放不下这件物品的时候,直接跳过这件物品 例如上例 普通递归 直接输入1次 # ,并按下 space 后,将生成1级标题。 输入2次 # ,并按下 space 后,将生成2级标题。 以此类推,我们支持6级标题。有助于使用 TOC 语法后生成一个完美的目录。 记忆搜索式递归 强调文本 强调文本 加粗文本 加粗文本 标记文本 删除文本 引用文本 H 2 O is是液体。 2 10 运算结果是 1024.

AcWing 10 有依赖的背包问题

匿名 (未验证) 提交于 2019-12-02 23:43:01
N V 物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。 如下图所示: 如果选择物品5,则必须选择物品1和2。这是因为2是5的父节点,1是2的父节点。 i v i w i p i 1 … N 1…N。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 N , V N,V,用空格隔开,分别表示物品个数和背包容量。 N i v i , w i , p i vi,wi,pi,用空格隔开,分别表示物品的体积、价值和依赖的物品编号。 p i = 1 输出格式 输出一个整数,表示最大价值。 数据范围 1 ≤ N , V ≤ 100 1≤N,V≤100 1 ≤ v i , w i ≤ 100 1≤vi,wi≤100 父节点编号范围: 内部结点: 1 ≤ p i ≤ N 1≤pi≤N; p i = 1 输入样例 5 7 2 3 -1 2 2 1 3 5 1 4 7 2 3 6 2 输出样例: 11背包九讲中有依赖的背包问题 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 105; int N, V, p, root, ind=0; int v[maxn], w[maxn];