目录
01背包问题例题引入
蓝桥杯国赛真题
蓝桥杯2195题.费用报销
蓝桥杯2201题.搬砖
01背包问题和最值问题离不开,最值问题嘛,就又和动态规划离不开,大家不太了解动态规划的可以看我之前写的文章,基础版里面有动态规划的模板。
动态规划算法详解基础篇-CSDN博客
动态规划算法详解进阶篇-CSDN博客
01背包问题例题引入
有 N 件物品和一个容量是 V 的背包。每种物品只有一件。
第 i 件物品的体积是 V[i],价值是 W[i]。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大,输出最大价值。
/*
1、定义dp含义: dp[i][v]: 在0...i中,体积为v的背包中能够拿到的最大价值为dp[i][v]
2、关系式: dp[i][v] = ?
1) 对于第i件物品,如果我们决定不把它放进背包里,那么就是dp[i - 1][v]
2) 对于第i件物品,如果我们把它放进背包里,那么就是dp[i - 1][v - w[i]] + v
综合起来就是 dp[i][v] = Math.max(dp[i - 1][v], dp[i - 1][v - w[i]] + v);
3、初始化条件:dp[0][v] = 0; dp[i][0] = 0;
*/
import java.util.Scanner;
public class Bag {
public static void main(String[]args){
Scanner scan = new Scanner(System.in);
//物品数量
int N = scan.nextInt();
//背包容量
int V = scan.nextInt();
//第i个元素表示第i个物品的体积
int[]v = new int[N + 1];
//第i个元素表示第i个物品的价值
int[]w = new int[N + 1];
for(int i = 1; i <= N; i++){
//接下来有N行,每行有两个整数v[i],w[i]
v[i] = scan.nextInt();
w[i] = scan.nextInt();
}
scan.close();
//核心代码
int[][]dp = new int[N + 1][V + 1];
/*
这个双层for循环的j表示背包的容量。
在这个循环中,我们遍历了所有可能的背包容量(从0到V),然后根据当前物品的体积和价值来更新dp数组。
具体来说,对于每个物品i和背包容量j,我们有以下两种情况:
如果当前物品的体积大于背包容量j,那么我们不能将这个物品放入背包,
所以dp[i][j] = dp[i-1][j],即不选择当前物品的最大价值。
如果当前物品的体积小于等于背包容量j,那么我们可以选择是否将这个物品放入背包。
如果我们选择放入背包,那么背包的剩余容量为j - v[i],此时的最大价值为dp[i-1][j-v[i]] + w[i];
如果我们选择不放入背包,那么背包的最大价值为dp[i-1][j]。我们需要在这两种情况下选择一个最大值作为dp[i][j]的值。
*/
for(int i = 1; i <= N; i++){
for(int j = 0; j <= V; j++){
if(v[i] > j){
dp[i][j] = dp[i - 1][j];
}
else{
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
}
}
System.out.println(dp[N][V]);
}
}
}
蓝桥杯国赛真题
蓝桥杯历年真题中有5道关于背包问题的,其中01背包问题占两道。
蓝桥杯2195题.费用报销
3.费用报销 - 蓝桥云课 (lanqiao.cn)
题解:
代码定义了一些变量和数组,包括一个StreamTokenizer对象用于读取输入,一个二维数组input用于存储每个任务的开始时间和所需时间,一个二维布尔数组dp用于存储每个任务是否可以在给定的时间内完成,以及一些常量N和M。
在run()方法中,首先读取输入的任务数量n、最大天数m和最小间隔k。然后,对于每个任务,读取其开始时间和所需时间,并将其存储在input数组中。接着,使用自定义的比较器MyComparator对input数组进行排序,以便按照任务的开始时间进行排序。
接下来,初始化dp数组的第一行和第一列为true,表示没有任务时也可以完成0个任务。然后,遍历每个任务,对于每个任务,找到在其开始时间之前且结束时间与当前任务开始时间之差大于等于k的任务,更新dp数组。最后,找到dp数组最后一列的最大值,即为最多可以完成的任务数量。
最后,输出最多可以完成的任务数量。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Comparator;
public class Test1 {
public static void main(String[] args) {
new Test1().run();
}
StreamTokenizer streamTokenizer = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
int nextInt() {
try {
streamTokenizer.nextToken();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return (int)streamTokenizer.nval;
}
int N = 1010, M = 5010;
int[] days = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int[][] input = new int[N][2];
boolean[][] dp = new boolean[N][M];
void run() {
int n = nextInt(), m = nextInt(), k = nextInt();
for(int i = 1; i <= 12; i++) {
days[i] += days[i - 1];
}
for(int i = 1; i <= n; i++) {
input[i][0] = days[nextInt() - 1] + nextInt();
input[i][1] = nextInt();
}
Arrays.sort(input, 1, n + 1, new MyComparator());
dp[0][0] = true;
int l = 0, max = 0;
for(int i = 1; i <= n; i++) {
while(input[i][0] - input[l + 1][0] >= k) l++;
for(int j = 0; j <= m; j++) {
dp[i][j] = dp[i - 1][j];
if(j >= input[i][1] && dp[l][j - input[i][1]]) {
dp[i][j] = true;
max = Math.max(max, j);
}
}
}
System.out.println(max);
}
class MyComparator implements Comparator<int[]>{
@Override
public int compare(int[] o1, int[] o2) {
// TODO 自动生成的方法存根
return o1[0] - o2[0];
}
}
}
蓝桥杯2201题.搬砖
4.搬砖 - 蓝桥云课 (lanqiao.cn)
题解:
-
首先,从标准输入读取物品的数量n,然后读取每个物品的价值和重量。同时,计算所有物品的总价值。
-
然后,使用自定义的比较器对物品进行排序。这个比较器基于一个规则:如果物品i的价值加上重量大于物品j的价值减去重量,那么物品i应该排在物品j之前。这个规则用于确定如何选择物品以最大化总价值。
-
初始化一个动态规划数组dp,其中dp[j]表示总重量不超过j时可以获得的最大价值。初始时,dp数组的所有元素都为0。
-
对于每个物品,从总价值开始向下遍历到物品的重量。如果当前的重量减去物品的重量小于等于物品的价值,那么就可以选择这个物品。在这种情况下,dp[j]的值应该是dp[j]和dp[j - arr[i][0]] + arr[i][1]中的较大值。这是因为我们可以选择这个物品,所以总价值会增加arr[i][1],而总重量会减少arr[i][0]。
-
在每次更新dp[j]后,都会检查并更新最大价值ans。
-
最后,输出最大价值ans。
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
new Test1().run();
}
int W = 20010, N = 1010, n;
int[] dp = new int[W];
int[][] arr = new int[N][2];
int sum = 0;
void run() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for(int i = 1; i <= n; i++) {
arr[i][0] = sc.nextInt();
arr[i][1] = sc.nextInt();
sum += arr[i][0];
}
sc.close();
Arrays.sort(arr, 1, n + 1, new Comparator<int[]>() {
//规律: vi - wj > vj - wi -> vi + wi > vj + wj
@Override
public int compare(int[] o1, int[] o2) {
// TODO Auto-generated method stub
return o1[0] + o1[1] - o2[0] - o2[1];
}
});
int ans = 0;
for(int i = 1; i <= n; i++) {
for(int j = sum; j >= arr[i][0]; j--) {
if(j - arr[i][0] <= arr[i][1]) {
dp[j] = Math.max(dp[j], dp[j - arr[i][0]] + arr[i][1]);
}
ans = Math.max(ans, dp[j]);
}
}
System.out.println(ans);
}
}