背包问题

背包九讲

穿精又带淫゛_ 提交于 2020-01-26 21:08:30
本篇文章设计的题目均在 AcWing 的2-12题。 一、01背包 要求 :每种物品只能选择0个或1个,即对于每种物品只有选或者不选两种情况。 题目描述 :( 题目链接 ) \quad 有 N N N 件物品和一个容量是 V V V 的背包。每件物品只能使用一次。第 i i i 件物品的体积是 v i v_i v i ​ ,价值是 w i w_i w i ​ 。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。 输入格式 : \quad 第一行两个整数, N , V N,V N , V ,用空格隔开,分别表示物品数量和背包容积。接下来有 N N N 行,每行两个整数 v i , w i v_i,w_i v i ​ , w i ​ ,用空格隔开,分别表示第 i i i 件物品的体积和价值。 输出格式 : \quad 输出一个整数,表示最大价值。 数据范围 : 0 < N , V ≤ 1000 0<N,V≤1000 0 < N , V ≤ 1 0 0 0 0 < v i , w i ≤ 1000 0<v_i,w_i≤1000 0 < v i ​ , w i ​ ≤ 1 0 0 0 输入样例 : 4 5 1 2 2 4 3 4 4 5 输出样例 : 8 思路1:二维数组记录 \quad f[i][j] 表示只看前 i 物品,总体积是 j

HDU ACM 2844 Coins (多重背包)----------------01背包,完全背包,多重背包模板

南笙酒味 提交于 2020-01-25 08:37:23
http://acm.hdu.edu.cn/showproblem.php?pid=2844 多重背包问题. 求出恰好能买的数目.最后找f[i]>0的背包有几个 或者 不需要恰好装满,最后搜索f[i] == i 的数目 //背包模版 1 #include <iostream> 2 using namespace std; 3 const int MAX = 100000 + 10; 4 const int INF = 0x7fffffff; 5 int f[MAX]; 6 int v; 7 void ZeroOnePack(int cost,int weight) 8 { 9 int i; 10 for(i=v;i>=cost;i--) 11 { 12 f[i] = max(f[i],f[i-cost]+weight); 13 } 14 } 15 void CompletePack(int cost,int weight) 16 { 17 int i; 18 for(i=cost;i<=v;i++) 19 { 20 f[i] = max(f[i],f[i-cost]+weight); 21 } 22 } 23 void MultiplePack(int cost,int weight,int amount) 24 { 25 if(v <= cost*amount) 26 { 27

01背包问题

好久不见. 提交于 2020-01-25 08:36:30
背包九讲奉上 http://love-oriented.com/pack/P01.html 以HDU 2602为例: http://acm.hdu.edu.cn/showproblem.php?pid=2602 初始化的细节问题 我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。 如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。 如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。 为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。 一个常数优化 前面的伪代码中有 for v=V..1,可以将这个循环的下限进行改进。 由于只需要最后f[v]的值,倒推前一个物品

0-1背包问题变形------------cow exhibition

∥☆過路亽.° 提交于 2020-01-25 08:26:06
1365: Pku2184 Cow exhibition Description Bessie要从她的N头奶牛中选出一些奶牛去参加展览,她已经给出了每头奶牛的两个指标,Si和Fi(-1000<=Si,Fi<=1000),分别代表每头奶牛的聪明指数和快乐指数。当然她希望所挑选奶牛的Si和Fi的总和最大,而且为了显示她的奶牛是全面发展的,Si和Fi各自的和数不能小于0。 Input 第1行:奶牛总数N ,N<=100 第2到N+1行:每头奶牛的Si和Fi Si (-1000 <= Si <= 1000) Fi (-1000 <= Fi <= 1000) Output 符合条件的Si和Fi的最大总和 Sample Input 5 -5 7 8 -6 6 -3 2 1 -8 -5 Sample Output 8这道题是一道比较经典的01背包的变形题 Dominos这道题也是一道类似的题目, 还可以用搜索来做。把有利的值统统加入,同时记下可能使不符合的元素,做一次排除,找到正确的最优值。 0-1背包有时(分堆)可以用随机贪心来做的,大致思路是从多的一堆中随机一个放入少的一堆中。 所以这道题最坑的地方 初始化要将 数组 f 赋值为 -0x3fffffff(其实-200000就够了) 并把f[1000000] = 0 因为幽默度能可能出现 负数。 见代码 #include<bits/stdc++

背包问题克星——分组背包

烈酒焚心 提交于 2020-01-24 21:59:38
背包问题克星——分组背包 有N件物品,告诉你这N件物品的重量以及价值,将这些物品划分为K组,每组中的物品互相冲突,最多选一件,求解将哪些物品装入背包可使这些物品的费用综合不超过背包的容量,且价值总和最大。 算法: 首先判断一个分组当中的一件物品,同01背包一样,此物品存在两种状态,取与不取,若取此物品,则继续判断下一组的第一件物品,若不取此物品,则继续判断本组下一件物品,若该物品为本组最后一件物品,则判断下一组。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}。使用一维数组的伪代码如下: for 所有的组k for v=V..0 for 所有的i属于组k f[v]=max{f[v],f[v-c[i]]+w[i]} 分组的背包问题将彼此互斥的若干物品称为一个组,这建立了一个很好的模型。不少背包问题的变形都可以转化为分组的背包问题由分组的背包问题进一步可定义“泛化物品”的概念,十分有利于解题。例题:hdu1712 例题: 一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,…,Wn,它们的价值分别为C1,C2,…,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量

十二、背包问题

£可爱£侵袭症+ 提交于 2020-01-24 16:33:56
12.1 0/1 背包问题 12.1.1 题目模型 有 N 件物品和一个容量为 V 的背包。第 i 件物品的体积是 v[i] ,价值是 cost[i] 。求解将哪些物品装入背包可使价值总和最大。 12.1.2 基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 用子问题定义状态:即 f[i][j] 表示前 i 件物品恰放入一个容量为 j 的背包可以获得的最大价值 。则其状态转移方程便是: f[i][j]=max{f[i-1][j],f[i-1][j-v[i]]+cost[i]} 这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下: “将前 i 件物品放入容量为 j 的背包中”这个子问题,若只考虑第 i 件物品的策略(放或不放),那么就可以转化为一个只牵扯前 i-1 件物品的问题。 如果 不放第 i 件物品 ,那么问题就转化为“前 i-1 件物品放入容量为 j 的背包中”,价值为 f[i-1][j] ; 如果 放第 i 件物品 ,那么问题就转化为“前 i-1 件物品放入剩下的容量为 j-v[i] 的背包中”,此时能获得的最大价值就是 f[i-1][j-v[i]] + cost[i] 。 12.1.3 例题 Description 给定 n 种物品和一个容量为 V 的背包,物品 i 的体积是 \(v_i\)

背包问题

耗尽温柔 提交于 2020-01-23 21:49:33
# include <stdio.h> # include <algorithm> using namespace std ; struct good { int w ; //重 int v ; //价值 } good [ 101 ] ; int dp [ 101 ] [ 1001 ] ; //状态数组 int main ( ) { int s , n ; //价值 数量 while ( scanf ( "%d%d" , & s , & n ) != EOF ) { for ( int i = 1 ; i <= n ; i ++ ) scanf ( "%d" , & good [ i ] . w , & good [ i ] . v ) ; for ( int i = 0 ; i <= s ; i ++ ) dp [ 0 ] [ i ] = 0 ; //初始化,初始没有物品时总体积不超过j时最大价值为0 for ( int i = 1 ; i <= n ; i ++ ) { for ( int j = s ; j >= good [ i ] . w ; j -- ) //对s到good[i].w之间的任何一个j转移来源为dp[i-1][j]或dp[i-1][j-good[i].w]+good[i].v,取其中较大者 dp [ i ] [ j ] = max ( dp [ i - 1

树形依赖背包的两种做法

半城伤御伤魂 提交于 2020-01-22 08:59:05
  今天才发现自己根本不会树形背包,我太菜了。   一般的树形背包是这样做的:   看上去,它的复杂度是 $O(nk^2)$ 的。 第一种优化:   这里,如果第二维的大小和子树大小有关,同时又不超过一个常数 $k$ 。例如:第二维表示子树内选了多少个点,那么通过一些精妙的分析和上界优化,复杂度就可以变成 $O(nk)$ 了。   以下的 $siz_x$ 表示合并 $son$ 这个子树前 $x$ 子树的大小(注意:不是 $x$ 的真实子树大小,这里很重要)。   这样分析出来的复杂度就是 $O(nk)$ .   证明:摘自 这里 ;   首先,定义 $T(n)$ 为处理 $n$ 这棵子树时所用的时间,$f(n)$ 为处理 $n$ 这个点时所用的时间。   $T(x)=\left(\sum_{f_y=x} T_{y}\right)+f(x)\\f(x)=\min(m,siz(y_1))\times \min(m,siz(y_1))+\min(m,siz(y_1)+siz(y_2))\times \min(m,siz(y_1))\\ ~~~~~~~~~~~+\cdots+\min(m,siz(x))\times \min(m,siz(y_n))$   现在进行一番放缩,把每个乘法的前一项统一变成 $\min(m,siz(x))$ ,这样显然只会使答案变大

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

倖福魔咒の 提交于 2020-01-21 14:28:44
算法:二进制优化,动态规划 #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; } 来源: https://www.cnblogs.com/programyang/p/11241585.html

POJ - 2063 Investment 背包问题

青春壹個敷衍的年華 提交于 2020-01-21 09:30:37
题目链接:http://poj.org/problem?id=2063 题目大意:直到收到公证人的信,约翰才知道他有一个叔祖父。他得知他已故的伯祖父在南美洲某处收集了一大笔钱,而约翰是唯一的继承人。 约翰暂时不需要那么多钱。但他意识到,将这笔资金存放在一个安全的地方,并让它增长,直到他决定退休,这将是一个好主意。银行使他相信某种债券对他来说是有趣的。 这种债券有固定的价值,每年支付固定数额的利息,在每年年底支付给所有者。这种债券没有固定期限。债券有不同大小可供选择。大的通常利息比较高。不久,约翰意识到,购买债券的最佳组合不是那么简单。而且,几年之后,他的资本就会增长,而日程安排也不得不重新评估。 假设有以下债券: 价值的年度 感兴趣 4000 3000 400 250 资本为1万埃的人可以买两张4 000美元的债券,年息为800美元。购买两支3000美元的债券和一支4000美元的债券是一个更好的主意,因为它每年的利息是900美元。两年后,资本增长到11800美元,出售3000美元的资产并购买4000美元的资产是有道理的,因此年利息增长到1050美元。这就是这个故事不太可能发生的地方:该银行不收取买卖债券的费用。明年的总数是12850美元,也就是4000美元的三倍,每年的利息是1200美元。 这里是你的问题:给定一开始的金额,几年的时间,一组债券的价值和利息,找出在给定的时期内