背包问题

DP之背包

ⅰ亾dé卋堺 提交于 2019-12-04 11:35:43
一.01背包: (以下均可用一维来写 即只能选择一次的物品装在一定容积的背包中。f[i][j]表示前i件物品在容积为j时的最大价值。 for(int i = 1; i <= n ; i++){   for(int j = v ; j >= 0 ; j--){     if (w[i]<=j )       f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]);     else       f[i][j]=f[i-1][v];   } } 有需要注意的的地方: 我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“ 恰好 装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在 初始化 的时候有所不同。 如果是第一种问法,要求恰好装满背包,那么在初始化时除了 F[0] 为 0 , 其它F[1~V ] 均设为 - ∞ ,这样就可以保证最终得到的 F[V ] 是一种 恰好 装满背包的最优解。 如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将 F[0~V ] 全部 设为 0 。 这是为什么呢?可以这样理解:初始化的 F 数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么 此时只有 容量为 0 的背包可以在什么也不装且价值为 0 的情况下被“恰好装满”

树上背包问题做题总结

狂风中的少年 提交于 2019-12-04 08:13:40
背包(一般是 \(01\) 背包吧)与树形 \(DP\) 的结合,第一维通常是节点编号,第二维通常是背包体积.由子节点向父节点转移的时候,就是一个普通的背包问题. \(T1\) :选课/ \(The\) \(more\) , \(The\) \(Better\) 洛咕 HDU(多组数据) 题意:给定一个 \(n\) 个节点的森林,带点权,选 \(m\) 个点的最大点权和,要求选子节点必须先选父节点. 分析:新建一个虚根,森林变成树.套路地,设 \(f[i][j]\) 表示以 \(i\) 点为根的子树内选择 \(j\) 个点的最大点权和.先不考虑父节点必须选的话, \(f[u][j]=max(f[u][j],f[u][j-k]+f[v][k])\) ,最后再考虑要先选父节点, \(f[u][j]=f[u][j-1]+a[u]\) . #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<map> #include<set> #define ll long long using namespace std; inline int read(){ int x=0,o=1;char ch=getchar();

hdu_1059(多重背包)

狂风中的少年 提交于 2019-12-04 06:59:53
多重背包的讲解: 多重背包问题https://blog.csdn.net/yandaoqiusheng/article/details/84782655 1 for (int i = 1; i <= n; i++) { 2 int num = min(p[i], V / w[i]); 3 for (int k = 1; num > 0; k <<= 1) { 4 if (k > num) k = num; 5 num -= k; 6 for (int j = V; j >= w[i] * k; j--) 7 f[j] = max(f[j], f[j - w[i] * k] + v[i] * k); 8 } 9 } 本题题解:由于没有空间的限制,只是价值的限制,那么直接考虑用价值作为容量,然后状态定义为在所给物品可以拆分成价值为j的可能性,所有状态除了dp[0] = 0,其他等于-1 状态转移: dp[j] = max(dp[j] , dp[j-k*v[i]]]) k 用上面二分的方法 本题代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int main() 6 { 7 int p[6]; 8 int cnt = 0; 9 while(~scanf("

背包问题

痴心易碎 提交于 2019-12-03 16:24:43
多重背包 题目描述 Description 你有一个容量为 \(M\) 的背包,和 \(N\) 种物品。 每种物品都有三个属性, \(v_i,w_i,c_i\) ,分别表示这种物品的体积、价值和件数。 你的任务是,从这些所给物品中,选出若干件,其体积之和不能超过背包容量,并且使所选物品的权值的和最大。 输入描述 Input Description 第一行两个整数 \(N,M\) 接下来 \(N\) 行每行三个数 \(v_i,w_i,c_i\) 描述第 \(i\) 件物品的属性 输出描述 Output Description 最大的权值和 样例输入 Sample Input 2 8 2 100 4 4 100 2 样例输出 Sample Output 400 数据范围及提示 Data Size & Hint 对于20%的数据, \(c_i=1\) 对于60%的数据, \(N,M \leq 500,c_i \leq 100\) 对于90%的数据, \(N,M \leq 3000\) 对于100%的数据 , \(N,M \leq 7000,c_i \leq 5000\) ,保证答案不超过 \(2147483647\) tip: 有多重背包的题目,数组一定要开大!!!!!! 不然会 WA 而不是 RE . 题解1: int n,m,tot; int f[7010],p[100010],v

C++贪心算法实现部分背包问题

£可爱£侵袭症+ 提交于 2019-12-03 10:25:21
_(:з」∠)_ 1 #include <cstdio> 2 #include <iostream> 3 #include <ctime> 4 #include <windows.h> 5 #include <algorithm> 6 #include <fstream> 7 using namespace std; 8 struct object 9 { 10 int no; 11 double weight; 12 double value; 13 double average; 14 }; 15 bool cmp(const object &x, const object &y) 16 { 17 return x.average > y.average;//从小到大排<,若要从大到小排则> 18 } 19 void greedySelector(int m,int W,int solution[],struct object object[]){ 20 int i = 0,V = 0,j = 0; 21 while(object[i].weight < W) 22 { 23 solution[i] = 1; 24 W = W - object[i].weight; 25 V = V + object[i].value; 26 i++; 27 } 28 V = V + (W

带权物品背包问题

馋奶兔 提交于 2019-12-03 07:31:22
也许更好的阅读体验 \(\mathcal{Description}\) 有 \(n\) 个物品,每个物品都有一个重量 \(w_i\) 和权值 \(v_i\) ,并给额外 \(m\) 个背包,每个背包有一个容量。 你需要选出若干个物品,并选出 同等数量 的背包将这些物品装进去,每个背包 只能装一个 物品,要求每个背包的容量都大于等于其内物品重量. 接下来,你需要将这些背包从左到右排成一排。如果任意相邻的两个背包,都满足左边背包中物品的重量 不超过 过右边背包中物品的重量, 同时 左边背包中物品的价值 不超过 右边背包中物品的价值。 问最多可以挑出多少个物品使其满足条件 \(n,m\leq 10^5\) \(\mathcal{Solution}\) 先将物品按照 \(w\) 从小到大排序 然后考虑从大到小将物品放进背包 设 \(f_i\) 表示以 \(i\) 号物品作为开头最长的序列长度 考虑第 \(i\) 个物品时,找到最小的可以放进去的背包,可以算出有多少个比它大的背包,设为 \(num\) 则 \(f_i=\min(num,\max\{f_{i+k}\})\) 用线段树或者树状数组维护后缀最大值即可 或者转成从大到小排序维护前缀最大值 \(\mathcal{Code}\) /******************************* Author:Morning_Glory

背包问题c++动态规划方式

懵懂的女人 提交于 2019-12-03 06:50:25
#include <iostream> using namespace std; int weight[5] = {5,2,4,8,6}; int len[5] = {2,4,3,1,7}; int num = 5; int space = 15; int main() { int max_weight[15] = {0}; for(uint32_t i=0; i<num;i++) { for(uint32_t j=space; j>len[i]; j--) { if (max_weight[j-len[i]] + weight[i] > max_weight[j]) { max_weight[j] = max_weight[j-len[i]] + weight[i]; } } for(uint32_t j=0; j<space; j++) { cout<<max_weight[j]<<" "; } cout<<endl; } cout<<max_weight[14]<<endl; return 0; }   结果 0 0 0 5 5 5 5 5 5 5 5 5 5 5 5 0 0 0 5 5 5 5 7 7 7 7 7 7 7 7 0 0 0 5 5 5 9 9 9 9 11 11 11 11 11 0 0 8 8 13 13 13 17 17 17 17 19 19 19 19

动态规划

为君一笑 提交于 2019-12-03 04:09:20
动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若⼲个⼦问题。但是经分解得到的⼦问题往往不是互相独⽴的 动态规划策略通常⽤于求解最优化问题。 – 在这类问题中,可能会有许多可⾏解。每⼀个解都对应于⼀个值,我们希望找到具有最优值的那个解,即最优解。 – 动态   • 在⼀定条件下,当前阶段的状态和下⼀阶段的状态之间的转移。 – 规划   • 建⽴状态转移⽅程(或称各阶段间的递推关系式),将各个阶段的状态以表格式⽅法存储。   • 表格式⽅法:⽤⼀个表来记录所有已解决的⼦问题的解 过程: • 阶段 stage   – 将所给问题的过程,按时间或空间特征分解成若⼲相互联系的阶段,以便按次序去求每阶段的解。 • 状态 state   – 各阶段开始时的客观条件叫做状态。 • 决策 decision   – 当各阶段的状态确定以后,就可以做出不同的决定,从⽽确定下⼀阶段的状态,这种决定称为决策。 • 状态转移 transition   – 根据上⼀阶段的状态和决策来导出本阶段的状态。 在分治法求解时,有些问题被重复计算了许多次 如果能够保存已解决的⼦问题的答案,⽽在需要时再找出已求得的答案,就可以避免⼤量重复计算,从⽽得到多项式时间算法。 基本要素 • 最优⼦结构(optimal substructure)   – 原问题的最优解包含了⼦问题的最优解。   – 该性质使我们能够以

动态规划 01背包问题

ぐ巨炮叔叔 提交于 2019-12-03 01:55:21
0-1背包 Description 给定n(n<=100)种物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。 Input 共有n+1行输入: 第一行为n值和c值,表示n件物品和背包容量c; 接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。 Output 输出装入背包中物品的最大总价值。 Sample Input 1 5 10 2 6 2 3 6 5 5 4 4 6 Sample Output 1 15 分析 :   n为有n个物品,c为背包空间   设dp[i][j]为在前i个物品中选择,背包空间为j时,装入的最大价值,初始化:边界0初始化为0,答案在dp[n][c]   如果当前j装得下 j >= obj_weight ,状态方程:   dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - obj_weight] + obj_price);   如果当前j装不下,状态方程:   dp[i][j] = dp[i - 1][j];   #include <iostream> using namespace std;

背包问题的递归和非递归算法

匿名 (未验证) 提交于 2019-12-03 00:34:01
/** 简单背包问题 问题定义: 有一个背包重量是S,有n件物品,重量分别是W0,W1...Wn-1 问能否从这n件物品中选择若干件放入背包中使其重量之和正好为S */ #include <iostream> #include <algorithm> #include <vector> #include <string> using namespace std; const int maxsize=100; int n,S;//n是有多少中物品,S是要凑足的重量 bool visit[maxsize];//标记是否被访问过,别访问过标记为1,没有访问过为0 int w[maxsize];//记录每一种物品的重量 int q[maxsize];//相当于一个栈,存储被访问过的物品的编号 int beibao() { int top=-1,begin=0,sum=0; int i; while(top!=-2) { //从第一个物品开始循环 for(i=begin;i<n;i++) { //如果没有被访问过,并且加上重量之和小于S if(!visit[i] && w[i]+sum<=S) { sum+=w[i];//在sum上加上当前物品的重量 q[++top]=i;//把物品的编号存入q[]中 begin=0;//从头开始访问 visit[i]=1;//该结点访问过标记 if(sum