01背包、有依赖的背包
前置知识: 讲解067、讲解06&-二维动态规划及其空间压缩技巧 【必备】课程的动态规划大专题从讲解066开始,建议从头开始学习会比较系统
本节课讲述: 01背包:每个物品 要和不要 两种可能性展开 有依赖的背包:多个物品变成一个复合物品(互斥),每件复合物品 要和怎么要 多种可能性展开 不能用01背包来解,但是非常重要的问题:非负数组前k个最小的子序列和问题(来自b站左神视频整理得出的笔记)明天更新分组背包
典型的背包模板
P1048 [NOIP2005 普及组] 采药
连接:[P1048 NOIP2005 普及组] 采药 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
提交441.67k
通过200.26k
时间限制1.00s
内存限制125.00MB
保存
难度普及−
历史分数100
相关讨论
查看讨论
推荐题目
题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入格式
第一行有 22 个整数 TT(1≤T≤10001≤T≤1000)和 MM(1≤M≤1001≤M≤100),用一个空格隔开,TT 代表总共能够用来采药的时间,MM 代表山洞里的草药的数目。
接下来的 MM 行每行包括两个在 11 到 100100 之间(包括 11 和 100100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出在规定的时间内可以采到的草药的最大总价值。
输入输出样例
输入 #1复制
70 3 71 100 69 1 1 2
输出 #1复制
3
说明/提示
【数据范围】
-
对于 30%30% 的数据,M≤10M≤10;
-
对于全部的数据,M≤100M≤100。
public static void main(String[] args) throws IOException { BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); String[] s = bf.readLine().split(" "); //总时间 int time = Integer.parseInt(s[0]); //种类 int n = Integer.parseInt(s[1]); int [] cost = new int[n+1]; int [] value = new int[n+1]; for (int i = 1;i<n+1;i++){ s = bf.readLine().split(" "); cost[i] = Integer.parseInt(s[0]); value[i] = Integer.parseInt(s[1]); } int ans = 0; int [][]dp = new int[n+1][time+1]; //当前从第一种草药开始,要或者不要 //先填好第一种草药 for (int i = 1;i<=n;i++){ //来到第i种草药 for (int j = 0;j<=time;j++){ //如果不要当前草药 dp[i][j] = dp[i-1][j]; //如果要当前草药 if (j -cost[i]>=0){ dp[i][j] = Math.max(dp[i-1][j-cost[i]]+value[i],dp[i][j]); } } } PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); out.print(dp[n][time]); out.close(); }
494. 目标和
已解答
中等
给你一个非负整数数组 nums
和一个整数 target
。
向数组中的每个整数前添加 '+'
或 '-'
,然后串联起所有整数,可以构造一个 表达式 :
-
例如,
nums = [2, 1]
,可以在2
之前添加'+'
,在1
之前添加'-'
,然后串联起来得到表达式"+2-1"
。
返回可以通过上述方法构造的、运算结果等于 target
的不同 表达式 的数目。
示例 1:
输入:nums = [1,1,1,1,1], target = 3 输出:5 解释:一共有 5 种方法让最终目标和为 3 。 -1 + 1 + 1 + 1 + 1 = 3 +1 - 1 + 1 + 1 + 1 = 3 +1 + 1 - 1 + 1 + 1 = 3 +1 + 1 + 1 - 1 + 1 = 3 +1 + 1 + 1 + 1 - 1 = 3
static int count ; public static int findTargetSumWays(int[] nums, int target) { int n = nums.length; count = 0; int sum = 0; for(int i:nums){ sum+=i; } // p = 正数和 // t = 负数和 //sum - p = t //target = p-t = p-(sum - p); //p = (sum+target)/2 if((sum+target)%2==1||sum<target){ return 0; } int p = (sum+target)/2; return process(nums,p); } //转换为了01背包问题 public static int process(int []nums,int p){ int n = nums.length; // int [][] dp = new int[n+1][p+1]; // dp[0][0] = 1; // for (int row = 1;row<=n;row++){ // for (int col = 0;col<=p;col++){ // dp[row][col] = dp[row-1][col]; // if ((col-nums[row-1])>=0){ // dp[row][col]+=dp[row-1][col-nums[row-1]]; // } // } // } int [] dp = new int[p+1]; dp[0] = 1; for (int i = 1;i<=n;i++){ for (int j = p;j>=0;j--){ if (j>=nums[i-1]){ dp[j]+=dp[j-nums[i-1]]; } } } return dp[p]; }
1049. 最后一块石头的重量 II
已解答
中等
提示
有一堆石头,用整数数组 stones
表示。其中 stones[i]
表示第 i
块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x
和 y
,且 x <= y
。那么粉碎的可能结果如下:
-
如果
x == y
,那么两块石头都会被完全粉碎; -
如果
x != y
,那么重量为x
的石头将会完全粉碎,而重量为y
的石头新重量为y-x
。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0
。
示例 1:
输入:stones = [2,7,4,1,8,1] 输出:1 解释: 组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1], 组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1], 组合 2 和 1,得到 1,所以数组转化为 [1,1,1], 组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
public int lastStoneWeightII(int[] stones) { int sum = 0; for(int i:stones){ sum+=i; } int near = near(stones,sum); return sum - near - near; } //二维动态规划数组压缩了 public static int near(int [] stones,int near){ int []dp = new int [near+1]; for(int i = 1;i<=stones.length;i++){ for (int j = near;j>=0;j--){ if(j - stones[i-1]>=0){ dp[j]=Math.max(dp[j],dp[j-stones[i-1]]+stones[i-1]); } } } return dp[near]; }