洛谷P1757通天之分组背包 大量注释,包含完整的分组背包动态转移方程说明

10 篇文章 1 订阅

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值