01.题目及链接
题目链接:https://www.luogu.com.cn/problem/P1757
02.分组背包介绍与状态转移方程
分组背包:有k组物品,N个物品,一个容量是C的背包。每组物品有若干个,同一组内的物品最多只能选一个。
状态转移方程:
定义状态: dp[k][j] 最大承重为j,有前k组物品可选时的最大价值
for (int k = 1; k <= groupNum; k++) {// 所属组k
for (int j = 0; j <= capacity; j++) {// 容量j
for (int i = 0; i < I; i++) {// 所属分组k的物品I
dp[k][j]=Math.max(dp[k - 1][j],
dp[k - 1][j - 物品i的重量] + 物品i的价值);
}
}
}
状态转移方程压缩
定义状态:dp[j] 最大容量为j的前提下,物品的最大价值
for (int k = 1; k <= groupNum; k++) {// 所属组k
for (int j = capacity; j >= 0; j--) {// 容量j
for (int i = 0; i < I; i++) {// 所属分组k的物品I
dp[j]=Math.max(dp[j], dp[j-data[i][0]]+data[i][1]);
}
}
}
03.题解
题解1:动态规划
public class P1757通天之分组背包3 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int capacity = in.nextInt();
int num = in.nextInt();
int[][] data = new int[num][3];
int groupNum = 0;// 有多少组
// data[i][0]物品的重量,data[i][1]利用价值,data[i][2]所属组数
for (int i = 0; i < num; i++) {
data[i][0] = in.nextInt();// 重量
data[i][1] = in.nextInt();// 价值
data[i][2] = in.nextInt();// 组数
groupNum = Math.max(groupNum, data[i][2]);// 组数
}
//dp[k][j] 最大承重为j,有前k组物品可选时的最大价值
int[][] dp = new int[groupNum + 1][capacity + 1];
for (int k = 1; k <= groupNum; k++) {// 所属组k
for (int j = 0; j <= capacity; j++) {// 容量j
List<Integer> tmpList=new ArrayList<>();
// 找到最大承重为j,有前k组物品可选时的最大价值
for (int i = 0; i < num; i++) {
if (data[i][2] == k) {
if (j >= data[i][0]) {
tmpList.add(Math.max(dp[k - 1][j],
dp[k - 1][j - data[i][0]] + data[i][1]));
} else {
tmpList.add(dp[k - 1][j]);
}
}
}
dp[k][j] =Collections.max(tmpList);
tmpList.clear();
}
}
System.out.println(dp[groupNum][capacity]);
in.close();
}
}
性能:时间:813ms 空间:42.62MB
题解2:动态规划+状态压缩
public class P1757通天之分组背包4 {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
int capacity=in.nextInt();
int num=in.nextInt();
int[][] data=new int[num][3];
int groupNum=0;//有多少组
// data[i][0]物品的重量,data[i][1]利用价值,data[i][2]所属组数
for (int i = 0; i < num; i++) {
data[i][0]=in.nextInt();//重量
data[i][1]=in.nextInt();//价值
data[i][2]=in.nextInt();//组数
groupNum=Math.max(groupNum, data[i][2]);//组数
}
//dp[j] 最大容量为j的前提下,物品的最大价值
int[] dp=new int[capacity+1];
for (int k = 1; k <= groupNum; k++) {//所属组k
for (int j = capacity; j >= 0; j--) {//容量j
for (int i = 0; i < num; i++) {
// 找到最大承重为j,有前k组物品可选时的最大价值
if(data[i][2]==k && j>=data[i][0]) {
dp[j]=Math.max(dp[j], dp[j-data[i][0]]+data[i][1]);
}
}
}
}
System.out.println(dp[capacity]);
in.close();
}
}
性能:时间:630ms 空间:21.88MB
可以明显看出,进行状态压缩后,代码的性能明显提高了,内存消耗明显降低了
PS:如果觉得该博客对各位大佬有所帮助,麻烦点个赞,各位的支持是我这个渣渣写博客的最大动力
04.更多背包学习
https://blog.csdn.net/qq_46237746/article/details/123908504