背包问题

动态规划-背包问题

瘦欲@ 提交于 2019-11-29 19:23:04
一、题目描述 有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值,问最多能装入背包的总价值是多大? 样例 样例 1: 输入: m = 10, A = [2, 3, 5, 7], V = [1, 5, 2, 4] 输出: 9 解释: 装入 A[1] 和 A[3] 可以得到最大价值, V[1] + V[3] = 9 样例 2: 输入: m = 10, A = [2, 3, 8], V = [2, 5, 8] 输出: 10 解释: 装入 A[0] 和 A[2] 可以得到最大价值, V[0] + V[2] = 10 挑战 O(nm) 空间复杂度可以通过, 不过你可以尝试 O(m) 空间复杂度吗? 注意事项 A[i], V[i], n, m 均为整数 你不能将物品进行切分 你所挑选的要装入背包的物品的总大小不能超过 m 每个物品只能取一次 二、代码 class Solution { public: /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @param V: Given n items with value V[i] * @return: The maximum value *

J. Stone game(背包问题)

拈花ヽ惹草 提交于 2019-11-29 17:37:14
题:https://nanti.jisuanke.com/t/41420 定义 dp[x][y] 表示第 x 个数到最后一个数能组成和为 y 的方案数 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=303; const int M=150000; const int mod=1e9+7; int dp[N][M]; int a[N]; int main(){ int t; scanf("%d",&t); while(t--){ int n,sum=0; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum+=a[i]; } sort(a+1,a+1+n); for(int i=0;i<=sum;i++) dp[n+1][i]=0; int ans=0; dp[n+1][0]=1; for(int i=n;i>=1;i--){ for(int j=0;j<=sum;j++){ dp[i][j]=dp[i+1][j]; if(j>=a[i]){//刚好能加当前的a[i],和为j dp[i][j]+=dp[i+1][j-a[i]]; //加之前的是因为dp[i][j]可能有多个来源

[算法模版]树形背包

人盡茶涼 提交于 2019-11-29 14:26:52
[算法模版]树形背包 树形01背包 树形01背包和普通背包不同点在于物品之间有相互的依赖关系。选取儿子物品的必要条件是选取了所有他的祖先。 我们考虑使用 dp[i][j] 代表第 i 个点的子树内,花费了 j 个容量能得到的最大权值。 伪代码: for(int i=1;i<=son;i++){//枚举所有儿子 dfs(son[i]);//先处理儿子 for(int j1=m;j1>=0;j1--){//枚举当前点用掉了多少容量(正着枚举会变成完全背包) for(int j2=0;j2<=j1;j2++){//枚举这个儿子分配多少 dp[i][j1]=max(dp[i][j1],dp[i][j1-j2]+dp[son[i]][j2]);//更新状态 } } } 显然,复杂度是 \(O(n*m^2)\) 的。 特殊情况的树形背包优化 当物品的体积全部为1时,我们可以把它优化到 \(O(n^2)\) 的复杂度。 来自lsj爷爷的代码: 乍一看根原来的没什么不同,但是需要注意,对于每一对点,都只会在他们的LCA被枚举到一次。可以自己想想为什么。 复杂度 \(n^2\) 。 例题 树形01背包优化 有一种方法可以把它优化到 \(n*m\) 的复杂度。 咕咕咕 参考资料 树上背包的上下界优化 【算法讲堂】【电子科技大学】【ACM】树形背包问题 将树形01背包优化到O(n*m) 来源:

9.13 Test——NOIP模拟赛

孤街浪徒 提交于 2019-11-29 13:40:39
T1:backpack NYG的背包 【问题描述】 NYG有一个神奇的背包,每放进去一个物品,背包的体积就会变大。 也就是说,每放进一个物品,背包会被占用一定的体积,但是紧接着背包的总体积又会增大一定的值(注意是在放入物品后背包总体积才增大)。 NYG发觉这个背包十分好用,于是不由自主地想到了一个问题。 现在给出背包初始容量V 以及n个物品,每一个物品两个值a, b,分别表示物品所占体积 和放入背包后背包增大的体积。 NYG想知道能否把所有物品装进去? 因为NYG比较老实,这么简单的问题自然装作不会做的样子。 于是他来请教你。 【输入格式】 从文件backpack.in中读入数据 输入文件包含多组数据。 第一行一个数T表示数据组数。 对于每组数据,第一行两个数n, h,接下来n行每行两个数a, b表示物品所占体积和放入背包后背包增大的体积。 【输出格式】 输出到文件backpack.out中 对于每一组数据,如果能把所有物品装进去,输出"Yes",否则输出"No"(不包含引号) 【样例输入1】 3 5 3 1 4 8 8 3 【样例输出1】 Yes 【样例输入2】 3 7 9269 21366 1233 7178 23155 16679 23729 15062 28427 939 6782 24224 9306 22778 13606 5 22367 17444 5442

背包九讲学习 + 自己的理解

自古美人都是妖i 提交于 2019-11-29 12:39:40
背包九讲 1. 01背包 题目: 分析: 动态规划也就是一种用子问题去最优化原问题的策略。所以作为非常简单但重要的01背包问题,也是先考虑子问题。我们要求考虑 n 个物品装在容量为 V 的背包中的最大价值, 很容易想到其 子问题 就是 ① n-1 个物品装在未装第n个物品容量为 V 的背包中的最大价值。 ② n-1 个物品装在已经装了第n个物品容量为 V-w[i] 的背包中的最大价值。 我们可以细想一下, 考虑第1 个物品时,我们用算出来背包装它和背包不装它的最优解, 对于第2个物品我们在子问题最优解确定的基础上(即前1个物品时的最优解确定)比较背包装2的基础上装1和背包不装2时装1的最优解。 对于3物品,我们考虑背包装3的基础上考虑1和2和背包不装3时考虑1和2的最优解。 ...... 对于第n个物品,我们比较背包装n的基础上考虑前n-1个物品的价值和背包不装n时考虑前n-1个物品的价值,得到最优解。 代码: #include<iostream> using namespace std; typedef long long ll; const int MA=1e3+5; int w[MA],v[MA],dp[MA][MA]; int main() { int n,V; cin>>n>>V; for(int i=0;i<=n;++i){ for(int j=0;j<=V;++j){

[SDOI2017]苹果树 题解

可紊 提交于 2019-11-29 12:32:13
首先,观察题意,可以发现在最长链下再接一个点,结果一定更优。 也就是说,可以免费选一条最长链,之后正常选。 我们枚举选的最长链,然后算出剩下部分的最优解。 有4部分: 1、链上每个点都选一个。 2、链上剩下的部分。 3、链的左面。 4、链的右面。 1可以直接计算。 那么,我们需要先进行树形背包,然后再通过某方式将其余3个合并。 我们知道,在此问题中,合并2个背包是 \(O(k)\) 的; 但3个及以上则是 \(O(k^2)\) 的,无法承受。 所以,我们只能在计算中就把其中两个合并,这样就只需合并2个了。 可以发现,3和4是正常的树形背包,而2是一个贪心的问题。 但是,我们没有时间给链上的点排序,再贪心选择。 所以,只能将2转为正常的树形背包问题。 可以这样想:选x则要选fx,选x的第二个则要选x的第一个。 那么,我们可以把大于1的拆点,拆成1和a-1。连上父子关系。 不难发现,这样我们就只需要3,4两个合并了。 先考虑如何进行树形背包: 来源: https://www.cnblogs.com/lnzwz/p/11517807.html

背包问题

血红的双手。 提交于 2019-11-29 11:57:58
背包问题解决: 代码: public class KnapsackProblem { public static void main(String[] args) { int []w={1,4,3};//物品的重量 int []val={1500,3000,2000};//物品的价值 这里的val[i],就是前面的v[i] int m=4; int n=val.length; //创建一个二维数组 // v[i][j] 表示在前i个物品中能够装入容量为j的背包中的最大价值 int [][]v=new int[n+1][m+1]; //为了记录放入商品的情况,我们定一个二维数组 int[][] path=new int[n+1][m+1]; //初始化第一行第一列 默认数组第一行第一列为0 for(int i=0;i<v.length;i++){ v[i][0]=0;//设置第一列为0 } for(int i=0;i<v[0].length;i++){ v[0][i]=0;//设置第一行为0 } //根据前面得到的公式啦动态规划处理 for(int i=1;i<v.length;i++){//不处理第一行 i是从一开始的 for(int j=1;j<v[0].length;j++){//处理第一列,j从1开时 if(w[i-1]>j){ //因为我们程序i是从1开始的

leetcode中完全背包问题集合

谁都会走 提交于 2019-11-29 11:18:38
这两天在刷leetcode的动态规划的题目时,发现很多动态规划的题目怎么想都很难出递推公式,而看答案往往都感觉是精巧设计的,但是遇到类似的题目又不知从何下手,看了一天的博客和其他资料,发现这种类型的题目都是一类经典问题的变种:背包问题 背包问题主要有3种基本类型:01背包,完全背包,多重背包问题。 这里列出几个写的比较好的博客:大家可先行补充下基本知识(主要是leetcode中的题目不会让人立刻联想到是背包问题,所以看基本概念的目的是深入熟悉和记住递推公式的模板,方便套用)。 背包问题九讲 动态规划解决01背包问题 本文是总结leetcode中的背包变形问题的集锦,所以会不断更新,首先来看困扰我的leetcode中的二维递推公式的都长什么样: for (int i = 1; i <= m; i++) { for (int j = 0; j < n; j++) { dp[i] = min(dp[i], dp[i - coins[j]] + 1); } } 注意看红字所示,递推公式中会减去外层循环中的某个值,而不是我们常见的如下模板: for (int i = 1; i <= m; i++) { for (int j = 0; j < n; j++) { dp[i] = min( dp[i-1]+A[i] , dp[i]); } } 这种反减的模板套路就和背包问题很像

9.12(多米诺骨牌+道路修建+重建道路)

别说谁变了你拦得住时间么 提交于 2019-11-29 10:26:41
一道dp: 有两个限制条件时可以考虑将其中一个存到维度,另外一个作为值,但一定要理清楚哪个是要优先满足的 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1002 4 int dp[N][10005],a[N],b[N],d[N]; 5 int main() 6 { 7 memset(dp,0x3f3f3f,sizeof(dp)); 8 int n; 9 scanf("%d",&n); 10 for(int i=1;i<=n;i++) 11 { 12 scanf("%d%d",&a[i],&b[i]); 13 } 14 for(int i=1;i<=n;i++) d[i]=a[i]-b[i]; 15 dp[0][5000]=0;//肯定是没有值的,初始化一定要代转移方程看有没有问题 16 for(int i=1;i<=n;i++) 17 { 18 for(int j=-5000;j<=5000;j++)//先去找最小 19 dp[i][j+5000]=min(dp[i-1][j+5000+d[i]],dp[i-1][j+5000-d[i]]+1); 20 } 21 int ans=1002; 22 for(int i=0;i<=5000;i++) 23 { 24 ans=min(dp[n][i+5000]

完全背包问题

末鹿安然 提交于 2019-11-29 09:44:16
完全背包问题 有N 种物品和一个容量为V 的背包,每种物品都有无限件可用。放入第i 种物品的费用是Ci,价值是Wi。求解:将哪些物品装入背包,可使这些物品的耗费的费用总和不超过背包容量,且价值总和最大。 现在的问题在于每个物品都有无限种,因此不能像01背包那样决定i物品放或者不放,因为放的话有多种可能,0件,1件,2件...... 现在回顾01背包里的一维dp: 之所以01背包能缩小到一维dp,是因为我们考虑i的放与不放时,dp[j]与dp[j-Ci]都必须是在i-1的状态下,也就是说是i-1个物品放入j容量背包和i-1个物品放入j-Ci个物品的最大值问题。如果采用逆序,当进行到j时,由于j-Ci<j,因此还没更新,dp[j-Ci]还表示的是i-1时刻的状态。而如果采用正序的方式,当进行到j时,dp[j-Ci]已经更新了,表示的已经是i时刻的状态了,因此不能采用正序。 而在完全背包中,当我们考虑i物品时,如果不放1件,也就是说只有0~i-1这几种物品往j容量背包里放,这个状态下的最大值是dp[j],是i-1时刻的状态。而如果放,由于要考虑放1件,2件还是3件。。。。,因此不能使用i-1时刻的状态了,因为i-1时刻的状态中只有0~i-1共i种物品,而我们现在已经确定要放了,因此必须要是i时刻下的背包,也就是说dp[j-Ci]此时必须处于i时刻,而不能是i-1时刻。 因此