动态规划之背包模型

采药(01背包)


在这里插入图片描述
典型01背包模板题

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = (int) (2e5 + 10);
	static int[][] dp = new int[110][1100]; //最长不上升子序列
	static int k = 0, n = 0;
	static int[] t = new int[N];
	static int[] val = new int[N];
	static int cnt = 0;
	static int time = 0;
	public static void main(String[] args) throws Exception{
		String[] tm = br.readLine().split(" ");
		time = Integer.parseInt(tm[0]);
		n = Integer.parseInt(tm[1]);
		for(int i = 1; i <= n; i++) {
			String[] tv = br.readLine().split(" ");
			t[i] = Integer.parseInt(tv[0]);
			val[i] = Integer.parseInt(tv[1]);
		}
		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= time; j++) {
				if(t[i] > j) {
					dp[i][j]  = dp[i - 1][j];
				}else {
					dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - t[i]] +val[i]);
				}
			}
		}
		
		System.out.println(dp[n][time]);
	}
}

装箱问题(01背包)


在这里插入图片描述
本题可以从两个方向去思考:

法一:
给定n个物品,及每个物品对应的体积,要让剩余空间最少,就是求放进去的体积的体积的最大值。我们将每个物品的体积当作背包的价值,不就等价于之前的求背包的最大价值了。
最后用总的体积-dp[n][vv]

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int[][] dp = new int[100][21000];
	static int[] v = new int[21000];
	static int n = 0,vv = 0;
	static long ans = 0;
	public static void main(String[] args) throws Exception{
		vv = Integer.parseInt(br.readLine());
		n = Integer.parseInt(br.readLine());
		for(int i = 1; i <= n; i++) {
			v[i] = Integer.parseInt(br.readLine());
		}
//
//		for(int j = 0; j <= vv; j++) {
//			dp[0][j] = j;
//		}

		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= vv; j++) {
				dp[i][j] = dp[i - 1][j];
				if(j >= v[i]) {
					dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - v[i]] + v[i]);
				}
			}
		}
		System.out.println(vv - dp[n][vv]);
	}
}



法2:
直接设dp[i][j]代表前i个物品,体积为j的最少剩余空间。
初始化dp[0][j]代表前0件物品,体积为j,那么它的最少剩余空间就是j,初始化这些状态。
然后进行转移
在这里插入图片描述

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int[][] dp = new int[100][21000];
	static int[] v = new int[21000];
	static int n = 0,vv = 0;
	static long ans = 0;
	public static void main(String[] args) throws Exception{
		vv = Integer.parseInt(br.readLine());
		n = Integer.parseInt(br.readLine());
		for(int i = 1; i <= n; i++) {
			v[i] = Integer.parseInt(br.readLine());
		}

		for(int j = 0; j <= vv; j++) {
			dp[0][j] = j;
		}

		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= vv; j++) {
				dp[i][j] = dp[i - 1][j];
				if(j >= v[i]) {
					dp[i][j] = Math.min(dp[i][j],dp[i - 1][j - v[i]]);
				}
			}
		}
		System.out.println(dp[n][vv]);
	}
}




宠物小精灵之收服(二维费用01背包👍😘)


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

本题是01背包的拓展版-二维费用背包
与平时的01背包(一维费用背包的不同是多了一维代价)
一维费用背包我们一般只考虑背包体积是否放的下。
二维费用背包是:同时考虑了背包容积与背包承重。
针对于这个题目:
在这里插入图片描述
本题的两个花费分别是:
精灵球的数量和皮卡丘体力值
而获得的价值就是野生小精灵的数量,需要注意的是,匹拉丘的体力值不能为0,所以皮卡丘的体力值的范围为0-m-1,最后在找一个消耗体力值最小的即可。
需要注意的是,本题必须使用滚动数组优化掉一层,否则会MLE。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int[][] dp = new int[1100][510];
	static int[] v = new int[110]; //伤害
	static int[] w = new int[110]; //数量
	static int n = 0,m = 0,k = 0,num = 0;
	static long ans = 0;
	//dp[i][j][k]只考虑前i个,精灵球数量不超过j,皮卡丘体力值不超过k的最大值
	public static void main(String[] args) throws Exception{
		String[] nmk = br.readLine().split(" ");
		n = Integer.parseInt(nmk[0]); //精灵球数量
		m = Integer.parseInt(nmk[1]); //皮卡丘体力值
		num = Integer.parseInt(nmk[2]); //野生小精灵的数量
		
		for(int i = 1; i <= num; i++) {
			String[] wv = br.readLine().split(" ");
			w[i] = Integer.parseInt(wv[0]); 
			v[i] = Integer.parseInt(wv[1]);
		}
		
		for(int i = 1; i <= num; i++) {
			for(int j = n; j >= w[i]; j --) {
				for(int k = m - 1; k >= v[i]; k--) {
					dp[j][k] = Math.max(dp[j][k],dp[j - w[i]][k - v[i]] + 1);
				}
			}
		}
	
		int s = m;
		while(s > 0 && dp[n][m-1] == dp[n][s - 1]) {
			s--;
		}
		System.out.println(dp[n][m - 1] + " " + (m - s));
	}
}




数字组合(01背包)

在这里插入图片描述
首相可以想到枚举所有数字的选不选的情况,然后判断是否可行,但是肯定是过不了的,时间复杂度太高了。
每个数字都有选不选,那不就和每个物品都可以放入或者不放入背包差不多嘛,所以可以采用01背包进行求解。
在这里插入图片描述


public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = 110;
	static int M = 11000;
	static int[][] dp = new int[N][M];
	//前i个数 构成m的方案数
	static int n = 0, m = 0;
	static int[] a= new int[N];
	public static void main(String[] args) throws IOException {
		String[] nm = br.readLine().split(" ");
		n = Integer.parseInt(nm[0]);
		m = Integer.parseInt(nm[1]);
		String[] aa = br.readLine().split(" ");
		for(int i = 1; i <= n; i++) {
			a[i] = Integer.parseInt(aa[i - 1]);
		}
		dp[0][0] = 1;
 		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= m; j++) {
				dp[i][j] += dp[i - 1][j];
				if(a[i] <= j) {
					dp[i][j] += dp[i - 1][j - a[i]];
				}
			}
		}
		System.out.println(dp[n][m]);
	}
}

买书(完全背包)


在这里插入图片描述
因为每本书可以买多本,不需要考虑书本数量的限制,我们只需要考虑钱就行,所以是完全背包。
❗:一定要注意v那一维一定要从0开始,要不会导致有些状态转换不过来。

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int M = 1100;
	static int[] v = {0,10,20,50,100};
	static int[][] dp = new int[5][M];
	static int n = 0, m = 0;
	public static void main(String[] args) throws IOException {
		n = Integer.parseInt(br.readLine());
		dp[0][0] = 1; 
		for(int i = 1; i <= 4; i++) { //书
			for(int j = 0; j <= n; j++) { //money
				for(int k = 0; k <= j / v[i]; k++) { //num
					dp[i][j] += dp[i - 1][j - v[i]*k];
				}
			}
		}
		System.out.println(dp[4][n]); 
	}
}

优化版本完全背包:

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int M = 1100;
	static int[] v = {0,10,20,50,100};
	static int[] dp = new int[M];
	static int n = 0, m = 0;
	public static void main(String[] args) throws IOException {
		n = Integer.parseInt(br.readLine());
		dp[0] = 1; 
		for(int i = 1; i <= 4; i++) { //书
			for(int j = v[i]; j <= n; j++) { //money
				dp[j] += dp[j - v[i]];
			}
		}
		System.out.println(dp[n]); 
	}
}

货币系统(完全背包)

在这里插入图片描述
和上一题基本相同,需要注意数据范围,我们需要开long

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int M = 3100;
	static int[] v = new int[20];
	static long[] dp = new long[M];
	static int n = 0, m = 0;
	public static void main(String[] args) throws IOException {
		String[] nm = br.readLine().split(" ");
		n = Integer.parseInt(nm[0]);
		m = Integer.parseInt(nm[1]);
		for(int i = 1; i <= n; i++) {
			v[i] = Integer.parseInt(br.readLine());
		}
		dp[0] = 1;
		for(int i = 1; i <= n; i++) {
			for(int j = v[i]; j <= m; j++) {
				dp[j] += dp[j - v[i]];
			}
		}
		System.out.println(dp[m]); 
		
	}
}

货币系统(🔺👍)


在这里插入图片描述


其实就是看哪些数可以被其他数凑出来,就可以去掉,看最后还剩下几个数即可。
首先可以想到的,肯定是小的可以凑出大的,大的不可以凑比自己还小的数。因此我们先给所有数排序,还需要注意多组样例之间的初始化问题,以及dp边界条件赋值。dp[i]表示是否可以被表示出来
对于每个可以凑出来的dp[j]我们可以使n–,如果不可以被凑出来,我们就看看能不能用它去凑其他更大的数。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = (int) (3e4 + 10);
	static boolean[] dp = new boolean[N];
	static int[] a = new int[N];
	static int t = 0 , n = 0;
	static int Inf = 0x3f3f3f3f;
	public static void main(String[] args) throws IOException {
		t = Integer.parseInt(br.readLine().trim());
		while(t-- > 0) {
			for(int i = 0; i < N; i++) {
				dp[i] = false;
			}
			n = Integer.parseInt(br.readLine().trim());
			String[] aa = br.readLine().split(" ");
			for(int i = 1; i <= n; i++) {
				a[i] = Integer.parseInt(aa[i - 1]);
			}
			
			Arrays.sort(a,1,1+n);
			int ans = n;
			dp[0] = true;
			for(int i = 1; i <= n; i++) {
				if(dp[a[i]]) {
					ans--;
					continue;
				}
				for(int j = a[i]; j <= a[n]; j++) {
					dp[j] = dp[j] | dp[j-a[i]];
				}
			}
			System.out.println(ans);
			
		}
	}
}

庆功会(多重背包)

在这里插入图片描述

和完全背包差不多,只不过这个有数量限制,只要理解了01背包,其实本质都是一样的。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int[] v = new int[510];
	static int[] w = new int[510];
	static int[] s = new int[510];
	static long[][] dp = new long[510][6010];
	static int n = 0, m = 0;
	public static void main(String[] args) throws IOException {
		String[] nm = br.readLine().split (" ");
		n = Integer.parseInt(nm[0]);
		m = Integer.parseInt(nm[1]);
		for(int i = 1; i <= n; i++) {
			String[] vws = br.readLine().split(" ");
			v[i] = Integer.parseInt(vws[0]);
			w[i] = Integer.parseInt(vws[1]);
			s[i] = Integer.parseInt(vws[2]);
		}
		
		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= m; j++) {
//				dp[i][j] = dp[i - 1][j];
				for(int k = 0; k <= s[i]; k++) {
					if(k*v[i] <= j) {
						dp[i][j] = Math.max(dp[i][j],dp[i- 1][j - k*v[i]] + k * w[i]);
					}
				}
			}
		}
		System.out.println(dp[n][m]);
	}
}

混合背包问题(多重背包二进制优化为01背包👍⭐)

在这里插入图片描述

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int[] v = new int[1100];
	static int[] w = new int[1100];
	static int[] s = new int[1100];
	static long[][] dp = new long[1100][1100];
	static int n = 0, vv = 0;
	public static void main(String[] args) throws IOException {
		String[] nm = br.readLine().split (" ");
		n = Integer.parseInt(nm[0]);
		vv = Integer.parseInt(nm[1]);
		for(int i = 1; i <= n; i++) {
			String[] vws = br.readLine().split(" ");
			v[i] = Integer.parseInt(vws[0]);
			w[i] = Integer.parseInt(vws[1]);
			int num = Integer.parseInt(vws[2]);
			if(num == -1) {
				s[i] = 1;
			}else if(num == 0) {
				s[i] = vv/v[i]; 
			}else {
				s[i] = num;
			}
		}
		
		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= vv; j++) {
				for(int k = 0; k <= s[i]; k++) {
					if(k*v[i] <= j) {
						dp[i][j] = Math.max(dp[i][j],dp[i- 1][j - k*v[i]] + k * w[i]);
					}
				}
			}
		}
		out.println(dp[n][vv]);
//		out.flush();
	}
}

上面的代码思路是正确的,但是会TLE,下面我们采用二进制优化将多重背包优化为多个01背包。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int[] v = new int[1100];
	static int[] w = new int[1100];
	static int[] s = new int[1100];
	static long[] dp = new long[1100];
	static int n = 0, vv = 0;
	public static void main(String[] args) throws IOException {
		String[] nm = br.readLine().split (" ");
		n = Integer.parseInt(nm[0]);
		vv = Integer.parseInt(nm[1]);
		for(int i = 1; i <= n; i++) {
			String[] vws = br.readLine().split(" ");
			v[i] = Integer.parseInt(vws[0]);
			w[i] = Integer.parseInt(vws[1]);
			s[i] = Integer.parseInt(vws[2]);
		}
		for(int i = 1; i <= n; i++) {
			if(s[i] == 0) {
				//完全背包
				for(int j = v[i]; j <= vv; j++) {
					dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
				}
			}else {
				//01背包和多重背包
				if(s[i] == -1) {
					//01背包
					s[i] = 1;
				}
				
				//二进制优化
				for(int k = 1; k <= s[i]; k *= 2) {
					for(int j = vv; j >= k*v[i]; j--) {
						dp[j] = Math.max(dp[j],dp[j - k*v[i]] + k*w[i]);
					}
					s[i] -= k;
				}
				if(s[i] != 0) {
					for(int j = vv; j >= s[i]*v[i]; j--) {
						dp[j] = Math.max(dp[j],dp[j - s[i]*v[i]] + s[i]*w[i]);
					}
				}
			}
			
		}
		System.out.println(dp[vv]);
	}
}

二维费用的背包问题(模板题🔥⭐)

在这里插入图片描述

同时限制体积和重量,和一维费用背包差不多。只是多了一个重量限制,在开一维就可以,然后我们使用滚动数组优化,注意是01背包,倒着遍历。

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = 1100;
	static int[] v = new int[N];
	static int[] w = new int[N];
	static int[] m = new int[N];
	static int[] s = new int[1100];
	static long[][] dp = new long[110][110];
	static int n = 0, vv = 0,mm = 0;
	public static void main(String[] args) throws IOException {
		String[] nvm = br.readLine().split(" ");
		n = Integer.parseInt(nvm[0]);
		vv = Integer.parseInt(nvm[1]);
		mm = Integer.parseInt(nvm[2]);
		for(int i = 1; i <= n; i++) {
			String[] vmw = br.readLine().split(" ");
			v[i] = Integer.parseInt(vmw[0]);
			m[i] = Integer.parseInt(vmw[1]);
			w[i] = Integer.parseInt(vmw[2]);
		}
		
		for(int i = 1; i <= n; i++) {
			for(int j = vv; j >= v[i]; j--) {
				for(int k = mm; k >= m[i]; k--){
					dp[j][k] = Math.max(dp[j][k],dp[j-v[i]][k-m[i]] + w[i]);
				}
			}
		}
		
		System.out.println(dp[vv][mm]);
	}
	
}

潜水员(二维费用的背包问题⭐👍)!

在这里插入图片描述
在这里插入图片描述


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = (int) (3e4 + 10);
	static int[][][] dp = new int[1100][110][110];
	static int[] v = new int[1100];
	static int[] m = new int[1100];
	static int[] w = new int[1100];
	static int nn = 0 , vv = 0, mm = 0;
	static int Inf = 0x3f3f3f3f;
	public static void main(String[] args) throws IOException {
		String[] nvm = br.readLine().split(" ");
		nn = Integer.parseInt(nvm[0]);
		vv = Integer.parseInt(nvm[1]);
		mm = Integer.parseInt(nvm[2]);
		for(int i = 1; i <= nn; i++) {
			String[] vmw = br.readLine().split(" ");
			v[i] = Integer.parseInt(vmw[0]);
			m[i] = Integer.parseInt(vmw[1]);
			w[i] = Integer.parseInt(vmw[2]);
		}
//		for(int i = 1; i <= nn; i++) {
//			for(int j = vv; j >= v[i]; j--) {
//				for(int k = mm; k >= m[i]; k--) {
//					dp[i][j][k] = Math.max(Math.max(dp[i][j][k],dp[i - 1][j][k]),dp[i-1][j-v[i]][k-m[i]] + w[i]);
//				}
//			}
//		}
		
		for(int i = 1; i <= nn; i++) {
		for(int j = 0; j <= vv; j++) {
			for(int k = 0; k <= mm; k++) {
				dp[i][j][k] = dp[i-1][j][k];
				if(v[i] <= j && m[i] <= k) {
					dp[i][j][k] = Math.max(dp[i][j][k],dp[i-1][j-v[i]][k-m[i]] + w[i]);
				}
//				dp[i][j][k] = Math.max(dp[i - 1][j][k],dp[i-1][j-v[i]][k-m[i]] + w[i]);
			}
		}
	}
		System.out.println(dp[nn][vv][mm]);
	}
}

机器分配(分组背包)


在这里插入图片描述

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = 110;
	static int[][] a = new int[N][N];
	static int[][] c = new int[N][N];
	static long[][] dp = new long[N][N];
	//前i个公司,前j个设备的盈利
	static int n = 0, vv = 0,m = 0;
	static int[] ans = new int[N];
	public static void main(String[] args) throws IOException {
		String[] nm = br.readLine().split(" ");
		n = Integer.parseInt(nm[0]);
		m = Integer.parseInt(nm[1]);
		for(int i = 1; i <= n; i++) {
			String[] aa = br.readLine().split(" ");
			for(int j = 1; j <= m; j++) {
				a[i][j] = Integer.parseInt(aa[j - 1]);
			}
		}
		for(int i = 1; i <= n; i++) { //第i组
			for(int j = 0; j <= m; j++) { //容量
				for(int k = 0; k <= j; k++) { //第i组选第几个
					if(dp[i][j] < dp[i - 1][j - k] + a[i][k]) {
						dp[i][j] = dp[i-1][j-k] + a[i][k];
	                    c[i][j] = j-k;  //当前状态有i-1,j-k转换过来
					}
				}
			}
		}
		int p = m;
		int pos = n;
		while(p != 0){
			ans[pos] = p - c[pos][p];
			p = c[pos][p];
			pos --;
		}
		
		System.out.println(dp[n][m]);
		
		for (int i = 1; i <= n; i ++) {
	       System.out.println(i + " " + ans[i]);
	    }
	}
	
}

开心的金明(01背包)


在这里插入图片描述
01背包裸题

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = 31000;
	static long[] dp = new long[N];
	static int[] lev = new int[N];
	static long[] p = new long[N];
	static int n = 0, vv = 0,m = 0;
	public static void main(String[] args) throws IOException {
		String[] nm = br.readLine().split(" ");
		n = Integer.parseInt(nm[0]);
		m = Integer.parseInt(nm[1]);
		for(int i = 1; i <= m;i++) {
			String[] pl = br.readLine().split(" ");
			p[i] = Integer.parseInt(pl[0]);
			lev[i] = Integer.parseInt(pl[1]);
		}
		for(int i = 1; i <= m; i++) {
			for(int j = n; j >= p[i]; j--) {
				dp[j] = Math.max(dp[j],dp[(int) (j - p[i])] + lev[i] * p[i]);
			}
		}
		
		System.out.println(dp[n]);
	}
	
}

背包问题求方案数(01背包求方案数😔❓)


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int N = 1100;
	static int mod = (int) (1e9 + 7);
	static long[][] dp = new long[N][N];
	static long[][] g = new long[N][N];
	static int[] v = new int[N];
	static int[] w = new int[N];
	static int n = 0, vv = 0,m = 0;
	static long ans = 0;
	public static void main(String[] args) throws IOException {
		String[] nv = br.readLine().split(" ");
		n = Integer.parseInt(nv[0]);
		vv = Integer.parseInt(nv[1]);
		for(int i = 1; i <= n; i++) {
			String[] vw = br.readLine().split(" ");
			v[i] = Integer.parseInt(vw[0]);
			w[i] = Integer.parseInt(vw[1]);
		}
		g[0][0] = 1;
		
		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= vv; j++) {
				dp[i][j] = dp[i - 1][j];
				if(v[i] <= j) {
					dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - v[i]] + w[i]);
				}
			}
		}
		
		for(int i = 1; i <= n; i++) {
			for(int j = 0; j <= vv; j++) {
				if (dp[i][j] == dp[i - 1][j])
	                g[i][j] = (g[i][j] + g[i - 1][j]) % mod;
	            if (j >= v[i] && dp[i][j] == dp[i - 1][j - v[i]] + w[i])
	                g[i][j] = (g[i][j] + g[i - 1][j - v[i]]) % mod;
			}
		}
		for(int j = 0; j <= vv; j++ ) {
			if(dp[n][j] == dp[n][vv]) {
				ans = (ans + g[n][j]) % mod;
			}
		}
		System.out.println(ans);
	}
	
}

背包问题求具体方案(❓)


在这里插入图片描述

金明的预算方案(有依赖的背包👍⭐)

在这里插入图片描述

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main{
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	static int[][] dp = new int[100][32005];
	static int[] v1 = new int[80];
	static int[] p1 = new int[80];
	static int[][] pri = new int[32005][5];
	static int[][] w = new int[32005][5];
	static int[] count = new int[80];
	static int[] order = new int[80];
	static int n = 0,m = 0,vv = 0;
	static long ans = 0;
	static int cnt = 0;
	public static void main(String[] args) throws Exception{
		String[] nm = br.readLine().split(" ");
		n = Integer.parseInt(nm[0]);
		m = Integer.parseInt(nm[1]);
		for(int i = 1; i <= m; i++) {
			String[] vpq = br.readLine().split(" ");
			int vv = Integer.parseInt(vpq[0]);
			int pp = Integer.parseInt(vpq[1]);
			int qq = Integer.parseInt(vpq[2]);
			if(qq != 0) {
				int c = order[qq];
				++count[c];
				pri[c][count[c]] = vv;
				w[c][count[c]] = pp;
				
			}else {
				++cnt;
				v1[cnt] = vv;
				p1[cnt] = pp;
				order[i] = cnt;
			}
		}
//		for(int i = 1; i <= cnt; i++) {
//			System.out.println(count[i]);
//		}
		for(int i = 1; i <= cnt; i++) {
			for(int j = 0; j <= n; j++) {
				dp[i][j] = dp[i - 1][j]; //不选
				if(j >= v1[i]) { //只选主件
					dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - v1[i]] + p1[i]*v1[i]);
				}
				if(j >= v1[i] + pri[i][1]) {
					dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - v1[i] - pri[i][1]] + p1[i] *v1[i] + pri[i][1] * w[i][1]);
				}
				if(j >= v1[i] + pri[i][2]) {
					dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - v1[i] - pri[i][2]] + p1[i] *v1[i] + pri[i][2] * w[i][2]);
				}
				if(j >= v1[i] +pri[i][1] +pri[i][2]) {
					dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - v1[i] - pri[i][2] - pri[i][1]] + p1[i] *v1[i] + pri[i][2] * w[i][2] + pri[i][1] * w[i][1]);
				}
			}
		}
		
		System.out.println(dp[cnt][n]);

	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

释怀°Believe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值