蓝桥杯java-A组准备记录(实时更新)

动态规划

背包问题

2. 01背包问题 - AcWing题库

动态规划专题——背包问题_动态规划 背包_Iareges的博客-CSDN博客

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。

  • 输入格式:第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

  • 输出格式:输出一个整数,表示最大价值。

  • 数据范围:0<N,V≤1000,0<vi,wi≤1000

  • 输入样例

4 5
1 2
2 4
3 4
4 5
  • 输出样例:
8

算法分析

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int N = in.nextInt();
		int V = in.nextInt();
		int[] v = new int[N+1];
		int[] w = new int[N+1];
		for (int i = 1; i < N+1; i++) {
			v[i] = in.nextInt();
			w[i] = in.nextInt();
		}
		int[][] res = new int[N+1][V+1];
		for (int i = 1; i < N+1; i++) { //内外两层循环可以互换位置
			for (int j = 1; j < V+1; j++) {
				if(j < v[i]) res[i][j] = res[i-1][j]; //装不下第i个物品
				else res[i][j] = Math.max(res[i-1][j],res[i-1][j-v[i]]+w[i]);
			}
		}
		System.out.println(res[N][V]);
	}
}

每种物品只有放与不放的选择,i 遍历1~N表示只考虑前 i 个物品,每次遍历体积1~V的情况。针对 res[i][j] ,第 i 个物品放不下就之间取 res[i][j] ,放得下就判断 不放的 res[i-1][j] 还是放了的 res[i-1][j-v[i]]+w[i](腾出来第 i 个物品体积 v[i] 的空间) 值大。每次得到的都是在考虑前 i 个物品、体积不超过 j 的情况下最大的价值

f(i, j) 表示只考虑前 i 个物品、且总体积不超过 j 的范围下的 max 。有两种情况

  • 不选第 i 个物品 → f(i-1, j)
  • 选第 i 个物品 → 前 i-1 的部分是找最大值+第 i 个物品的价值 → f(i-1, j-vi) + w[i]。注意要是 j 比第 i 个的体积还小就放不下,这种情况不成立
  • 取上面两种情况的最大值

优化后

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int N = in.nextInt();
		int V = in.nextInt();
		int[] v = new int[N+1];
		int[] w = new int[N+1];
		for (int i = 1; i < N+1; i++) {
			v[i] = in.nextInt();
			w[i] = in.nextInt();
		}
		int[] f = new int[V+1];
		for (int i = 1; i < N+1; i++) { 
			for (int j = V; j >= v[i]; j--)
				f[j] = Math.max(f[j],f[j-v[i]]+w[i]);
		}
		System.out.println(f[V]);
	}
}

完全背包问题

3. 完全背包问题 - AcWing题库

在上面基础上,每次选第 i 个物品时,可以选0、1、2、…、[ j w [ i ] \frac{j}{w[i]} w[i]j]个。在上面的基础上再加一个 1~[ j w [ i ] \frac{j}{w[i]} w[i]j]循环即可
f [ i ] [ j ] = max ⁡ 0 ≤ k ≤ t f [ i − 1 ] [ j − k ⋅ w [ i ] ] + k ⋅ v [ i ] f[i][j]=\max_{0≤k≤t} f[i−1][j−k⋅w[i]]+k⋅v[i] f[i][j]=0ktmaxf[i1][jkw[i]]+kv[i]

for (int i = 1; i <= N; i++)
        for (int j = 1; j <= V; j++) {
            int t = j / w[i];
            for (int k = 0; k <= t; k++)
                f[i][j] = max(f[i][j], f[i - 1][j - k * w[i]] + k * v[i]);
        }

优化后

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int N = in.nextInt();
		int V = in.nextInt();
		int[] v = new int[N+1];
		int[] w = new int[N+1];
		for (int i = 1; i < N+1; i++) {
			v[i] = in.nextInt();
			w[i] = in.nextInt();
		}
		int[] f = new int[V+1];
		for (int i = 1; i < N+1; i++) { 
			for (int j = v[i]; j < V+1; j++)
				f[j] = Math.max(f[j],f[j-v[i]]+w[i]);
		}
		System.out.println(f[V]);
	}
}

其实将01背包问题的优化后算法的内层循环变成由小到大即可

多重背包问题

在上面两种的基础上,每次取的第 i 个物品可取的个数限制在 s[i] 和容量之间,能取到的个数为 t = m i n ( s [ i ] , j w [ i ] ) t=min(s[i],\frac{j}{w[i]}) t=min(s[i],w[i]j) ,对 k 取值再做一个小于的范围即可

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int N = in.nextInt();
		int V = in.nextInt();
		int[] v = new int[N+1];
		int[] w = new int[N+1];
		int[] s = new int[N+1];
		for (int i = 1; i < N+1; i++) {
			v[i] = in.nextInt();
			w[i] = in.nextInt();
			s[i] = in.nextInt();
		}
		int[] f = new int[V+1];
        for (int i = 1; i <= N; i++)
            for (int j = V; j >= 0; j--){
                for (int k = 1; k <= s[i] && k*v[i] <= j; k++)
                    f[j] = Math.max(f[j], f[j-k*v[i]] + k*w[i]); 
            }
		System.out.println(f[V]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值