网络舆情中心seo是什么化学名称
背包九讲
01背包
有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。
第 ii 件物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000输入样例
4 5 1 2 2 4 3 4 4 5
输出样例:
8
二维数组
import java.util.*;public class Main {// f[i][j] // 1.不选第i个物品 f[i][j]=f[i-1][j]// 2.选第i个物品 f[i][j]=f[i-1][j-v[i]]// f[0][0]=0;// f[i][j]=max(1,2);public static void main(String[] args) {Scanner in=new Scanner(System.in);int N=1010;int f[][]=new int[N][N];//前i个物品体积为j的时候的最大价值int v[]=new int[N];//体积int w[]=new int[N];//价值int n=in.nextInt();//数量int m=in.nextInt();//体积for(int i=1;i<=n;i++){v[i]=in.nextInt();w[i]=in.nextInt();}for(int i=1;i<=n;i++){for(int j=0;j<=m;j++){f[i][j]=f[i-1][j];//不选第i个物品if(j>=v[i])//选第i个物品f[i][j]=Math.max(f[i][j],f[i-1][j-v[i]]+w[i]);}}System.out.println(f[n][m]);}
}
一维数组
import java.util.*;public class Main {static final int N=1010;public static void main(String args[]){Scanner in=new Scanner(System.in); int n=in.nextInt();int m=in.nextInt();int v[]=new int[N];int w[]=new int[N];int dp[]=new int[N];for(int i=1;i<=n;i++){v[i]=in.nextInt();w[i]=in.nextInt();}/*将二维数组压缩成一维数组不断更新dp[j]从最大容量开始更新,否则会将上一次循环的给更新掉j前边的部分就是二维数组前i-1个的结果所以从后边开始更新就不会影响结果
如果使用顺序,会先更新f[4],再更新f[7],对于这个书包问题来讲,
就是有可能,在更新f[4]的时候,已经把这次能加的物品加进来了,
然后更新f[7]的时候,还有可能再加一次,所以必须使用逆序,
保证,f[4]是没有加入新物品前,背包里的最优解。*/for(int i=1;i<=n;i++){for(int j=m;j>=v[i];j--){// if(j>=v[i])可以优化到循环内部dp[j]=Math.max(dp[j],dp[j-v[i]]+w[i]);}}System.out.println(dp[m]);}
}
初始化情况
f[0] 的初始值是0 其余都是负无穷(正好装满的时候最大值)
除0外初始化为负无穷,那么仅刚好装下的位置是正数(从0加),其余位置为负数(从负无穷加)
求恰好装满的最大价值,需要枚举一遍。
f[] 的初始值都是0(<=m时的最大值)
完全背包问题
有 NN 种物品和一个容量是 VV 的背包,每种物品都有无限件可用。
第 ii 种物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000输入样例
4 5 1 2 2 4 3 4 4 5
输出样例:
10
完全背包和01背包的唯一区别就是一个物品可以用无限次
初始化跟01背包一样
import java.util.*;
public class Main{public static void main(String args[]){Scanner in=new Scanner(System.in);int N=1010;int n=in.nextInt();int m=in.nextInt();int dp[]=new int[N];int v[]=new int[N];int w[]=new int[N];for(int i=1;i<=n;i++){v[i]=in.nextInt();w[i]=in.nextInt();}for(int i=1;i<=n;i++){for(int j=v[i];j<=m;j++){
//从0开始因为每个物品可以重复放入
//可以省掉判断,放入循环中dp[j]=Math.max(dp[j],dp[j-v[i]]+w[i]);}}System.out.println(dp[m]);}
}
多重背包问题 I
有 NN 种物品和一个容量是 VV 的背包。
第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000<N,V≤100
0<vi,wi,si≤1000<vi,wi,si≤100输入样例
4 5 1 2 3 2 4 1 3 4 3 4 5 2
输出样例:
10
完全背包问题由于物品数量无限,在状态转移时,当考虑放入某个物品时,是基于当前物品已经考虑过的状态进行转移,与 0 - 1 背包和多重背包基于上一个物品的状态转移有所不同。
多重背包可以看作是01背包的延申 可以放入0,1,2,3······s
import java.util.*;public class Main {public static void main(String[] args) {Scanner in=new Scanner(System.in);int N=200;int n=in.nextInt();int m=in.nextInt();int dp[]=new int[N];int v[]=new int[N];int w[]=new int[N];int s[]=new int[N];for(int i=1;i<=n;i++) {v[i]=in.nextInt();w[i]=in.nextInt();s[i]=in.nextInt();}for(int i=1;i<=n;i++) {for(int j=m;j>=v[i];j--) {for(int k=1;k<=s[i]&&k*v[i]<=j;k++)dp[j]=Math.max(dp[j], dp[j-k*v[i]]+k*w[i]);}}System.out.println(dp[m]);}
}
多重背包问题 II
有 NN 种物品和一个容量是 VV 的背包。
第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N≤10000<N≤1000
0<V≤20000<V≤2000
0<vi,wi,si≤20000<vi,wi,si≤2000提示:
本题考查多重背包的二进制优化方法。
输入样例
4 5 1 2 3 2 4 1 3 4 3 4 5 2
输出样例:
10
import java.util.Scanner;public class Main {// 定义常量,N 用于存储分组后的物品数量,M 用于存储背包的最大容量static final int N = 12010, M = 2010;// n 表示物品的原始种类数,m 表示背包的容量static int n, m;// v 数组存储每个分组物品的体积,w 数组存储每个分组物品的价值static int[] v = new int[N];static int[] w = new int[N];// f 数组用于动态规划,存储不同容量下的最大价值static int[] f = new int[M];public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取物品的原始种类数和背包的容量n = scanner.nextInt();m = scanner.nextInt();// cnt 用于记录分组后的物品组数int cnt = 0;// 遍历每一种原始物品for (int i = 1; i <= n; i++) {// a 表示单个物品的体积,b 表示单个物品的价值,s 表示该物品的数量int a = scanner.nextInt();int b = scanner.nextInt();int s = scanner.nextInt();// k 用于二进制拆分,从 1 开始int k = 1;// 进行二进制拆分while (k <= s) {cnt++;// 计算当前分组的体积v[cnt] = a * k;// 计算当前分组的价值w[cnt] = b * k;// 减去已经拆分出去的物品数量s -= k;// 二进制倍数增加k *= 2;}// 如果还有剩余物品,单独作为一组if (s > 0) {cnt++;v[cnt] = a * s;w[cnt] = b * s;}}// 将分组后的物品组数赋值给 nn = cnt;// 0 - 1 背包一维优化for (int i = 1; i <= n; i++) {for (int j = m; j >= v[i]; j--) {// 状态转移方程,更新最大价值f[j] = Math.max(f[j], f[j - v[i]] + w[i]);}}// 输出背包容量为 m 时的最大价值System.out.println(f[m]);scanner.close();}
}
混合背包问题
有 NN 种物品和一个容量是 VV 的背包。
物品一共有三类:
- 第一类物品只能用1次(01背包);
- 第二类物品可以用无限次(完全背包);
- 第三类物品最多只能用 sisi 次(多重背包);
每种体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。
- si=−1si=−1 表示第 ii 种物品只能用1次;
- si=0si=0 表示第 ii 种物品可以用无限次;
- si>0si>0 表示第 ii 种物品可以使用 sisi 次;
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000
−1≤si≤1000−1≤si≤1000输入样例
4 5 1 2 -1 2 4 1 3 4 0 4 5 2
输出样例:
8
import java.util.Scanner;public class Main {// 定义数组的最大长度static final int MAX_LENGTH = 100010;// n 表示物品的种类数,m 表示背包的容量static int n, m;// v 数组存储物品的体积,w 数组存储物品的价值,f 数组用于动态规划static int[] v = new int[MAX_LENGTH];static int[] w = new int[MAX_LENGTH];static int[] f = new int[MAX_LENGTH];public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取物品的种类数和背包的容量n = scanner.nextInt();m = scanner.nextInt();// cnt 用于记录二进制拆分后物品的总数int cnt = 1;// 遍历每种物品for (int i = 1; i <= n; i++) {// a 表示单个物品的体积,b 表示单个物品的价值,s 表示该物品的数量int a = scanner.nextInt();int b = scanner.nextInt();int s = scanner.nextInt();// 处理特殊情况:若 s 为负数,将其视为 1 个物品if (s < 0) {s = 1;} // 若 s 为 0,将其视为完全背包问题,计算该物品最多能取的数量else if (s == 0) {s = m / a;}// 进行二进制拆分int k = 1;while (k <= s) {v[cnt] = a * k;w[cnt] = b * k;s -= k;k *= 2;cnt++;}// 处理剩余的物品if (s > 0) {v[cnt] = s * a;w[cnt] = s * b;cnt++;}}// 进行 0 - 1 背包的动态规划for (int i = 1; i < cnt; i++) {for (int j = m; j >= v[i]; j--) {f[j] = Math.max(f[j], f[j - v[i]] + w[i]);}}// 输出背包容量为 m 时能获得的最大价值System.out.println(f[m]);scanner.close();}
}
二维费用的背包问题
有 NN 件物品和一个容量是 VV 的背包,背包能承受的最大重量是 MM。
每件物品只能用一次。体积是 vivi,重量是 mimi,价值是 wiwi。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。
输出最大价值。输入格式
第一行三个整数,N,V,MN,V,M,用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。
接下来有 NN 行,每行三个整数 vi,mi,wivi,mi,wi,用空格隔开,分别表示第 ii 件物品的体积、重量和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N≤10000<N≤1000
0<V,M≤1000<V,M≤100
0<vi,mi≤1000<vi,mi≤100
0<wi≤10000<wi≤1000输入样例
4 5 6 1 2 3 2 4 4 3 4 5 4 5 6
输出样例:
8
import java.util.Scanner;public class Main {// 定义常量 N,用于数组的大小static final int N = 1005;// n 表示物品的数量,V 表示背包的体积容量,M 表示背包的重量容量static int n, V, M;// v 数组存储每个物品的体积,m 数组存储每个物品的重量,w 数组存储每个物品的价值static int[] v = new int[N];static int[] m = new int[N];static int[] w = new int[N];// f 数组用于动态规划,f[j][k] 表示体积为 j 且重量为 k 时的最大价值static int[][] f = new int[N][N];public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取物品数量、背包体积容量和背包重量容量n = scanner.nextInt();V = scanner.nextInt();M = scanner.nextInt();// 读取每个物品的体积、重量和价值for (int i = 1; i <= n; i++) {v[i] = scanner.nextInt();m[i] = scanner.nextInt();w[i] = scanner.nextInt();}// 进行动态规划,使用 0 - 1 背包的思路for (int i = 1; i <= n; i++) {for (int j = V; j >= v[i]; j--) {for (int k = M; k >= m[i]; k--) {// 状态转移方程,更新最大价值f[j][k] = Math.max(f[j - v[i]][k - m[i]] + w[i], f[j][k]);}}}// 输出体积为 V 且重量为 M 时的最大价值System.out.println(f[V][M]);scanner.close();}
}
分组背包问题
有 NN 组物品和一个容量是 VV 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vijvij,价值是 wijwij,其中 ii 是组号,jj 是组内编号。求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 N,VN,V,用空格隔开,分别表示物品组数和背包容量。
接下来有 NN 组数据:
- 每组数据第一行有一个整数 SiSi,表示第 ii 个物品组的物品数量;
- 每组数据接下来有 SiSi 行,每行有两个整数 vij,wijvij,wij,用空格隔开,分别表示第 ii 个物品组的第 jj 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000<N,V≤100
0<Si≤1000<Si≤100
0<vij,wij≤1000<vij,wij≤100输入样例
3 5 2 1 2 2 4 1 3 4 1 4 5
输出样例:
8
import java.util.Scanner;public class Main {// 定义常量 N,作为数组的最大容量static final int N = 110;// f 数组用于存储状态,f[i][j] 表示只从前 i 组物品中选,当前体积小于等于 j 的最大值static int[][] f = new int[N][N];// v 数组存储物品体积,w 数组存储物品价值,s 数组存储每组物品的个数static int[][] v = new int[N][N];static int[][] w = new int[N][N];static int[] s = new int[N];// n 表示物品的组数,m 表示背包的容量static int n, m;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取物品的组数和背包的容量n = scanner.nextInt();m = scanner.nextInt();// 读取每组物品的信息for (int i = 1; i <= n; i++) {s[i] = scanner.nextInt();for (int j = 0; j < s[i]; j++) {v[i][j] = scanner.nextInt();w[i][j] = scanner.nextInt();}}// 动态规划过程for (int i = 1; i <= n; i++) {for (int j = 0; j <= m; j++) {// 不选当前组物品的情况f[i][j] = f[i - 1][j];// 枚举当前组的每个物品for (int k = 0; k < s[i]; k++) {if (j >= v[i][k]) {// 更新最大价值f[i][j] = Math.max(f[i][j], f[i - 1][j - v[i][k]] + w[i][k]);}}}}// 输出结果System.out.println(f[n][m]);scanner.close();}
}
import java.util.Scanner;public class Main {// 定义常量 N,作为数组的最大容量static final int N = 110;// f 数组用于存储状态,f[j] 表示当前体积小于等于 j 的最大值static int[] f = new int[N];// v 数组存储物品体积,w 数组存储物品价值,s 数组存储每组物品的个数static int[][] v = new int[N][N];static int[][] w = new int[N][N];static int[] s = new int[N];// n 表示物品的组数,m 表示背包的容量static int n, m;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取物品的组数和背包的容量n = scanner.nextInt();m = scanner.nextInt();// 读取每组物品的信息for (int i = 0; i < n; i++) {s[i] = scanner.nextInt();for (int j = 0; j < s[i]; j++) {v[i][j] = scanner.nextInt();w[i][j] = scanner.nextInt();}}// 动态规划过程for (int i = 0; i < n; i++) {for (int j = m; j >= 0; j--) {// 枚举当前组的每个物品for (int k = 0; k < s[i]; k++) {if (j >= v[i][k]) {// 更新最大价值f[j] = Math.max(f[j], f[j - v[i][k]] + w[i][k]);}}}}// 输出结果System.out.println(f[m]);scanner.close();}
}