我是靠谱客的博主 霸气板栗,这篇文章主要介绍华为机试练习_16:购物单(有依赖的背包问题),现在分享给大家,希望可以做个参考。

1、题目描述

在这里插入图片描述

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

2、思路分析

1、本题属于依赖背包问题:
在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
有四种情况: 只取主件:f[i-1,j-a[i,0]]+a[i,0]*b[i,0] 取主件+附件1:f[i-1,j-a[i,0]-a[i,1]]+a[i,0]*b[i,0]+a[i,1]*b[i,1] 取主件+附件2:f[i-1,j-a[i,0]-a[i,2]]+a[i,0]*b[i,0]+a[i,2]*b[i,2] 既主件+附件1+附件2:f[i-1,j-a[i,0]-a[i,1]-a[i,2]]+a[i,0]*b[i,0]+a[i,1]*b[i,1]+a[i,2]*b[i,2] 含义: f[i,j]表示用j元钱,买第i类物品,所得的最大价值 a[i,0]表示第i类物品主件的价格 a[i,1]表示第i类物品第1个附件的价格 a[i,2]表示第i类物品第2个附件的价格 b[i,0],b[i,1],b[i,2]分别表示主件、第1个附件和第2个附件的重要度。 需要在满足金额money内,买到最大价值的物品。价值=价格*重要度

2、使用二维数组加状态方程:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { //购买物品的总钱数 int N = scanner.nextInt(); //希望购买的物品的数量 int M = scanner.nextInt(); //二维数组,第i行表示第i个物品的价值,列:0表示主键,1表示附件1,2表示附件2 int[][] V = new int[M + 1][3]; //二维数组,第i行表示第i个物品的重要程度,列:0表示主键,1表示附件1,2表示附件2 int[][] P = new int[M + 1][3]; for (int i = 1; i <= M; i++) { int v = scanner.nextInt(); int p = scanner.nextInt(); int q = scanner.nextInt(); if (q == 0) { //q=0代表是主件 V[i][0] = v; P[i][0] = p; } else { //q>0代表是附件,q代表附件所属的主件编号 if (V[q][1] == 0) { V[q][1] = v; P[q][1] = p; } else { V[q][2] = v; P[q][2] = p; } } } //下面正式开始动态规划算法 int[][] dp = new int[M + 1][N + 1]; /** * 1、钱够用的时候,买不买主键 * 2、钱够用的时候,买不买主键、附件1 * 3、钱够用的时候,买不买主键、附件2 * 4、钱够用的时候,买不买主键、附件1、附件2 * 5、钱不够用的时候,只买前i-1件商品 */ for (int i = 1; i <= M; i++) { for (int j = 10; j <= N; j +=10) { if (j >= V[i][0]) { dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0]] + V[i][0] * P[i][0]); } else if (j >= V[i][0] + V[i][1]) { dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][1]] + V[i][0] * P[i][0] + V[i][1] * P[i][1]); } else if (j >= V[i][0] + V[i][2]) { dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][2]] + V[i][0] * P[i][0] + V[i][2] * P[i][2]); } else if (j >= V[i][0] + V[i][1] + V[i][2]) { dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][1] - V[i][2]] + V[i][0] * P[i][0] + V[i][1] * P[i][1] + V[i][2] * P[i][2]); } else { dp[i][j] = dp[i - 1][j]; } } } System.out.println(dp[M][N]); } } }

不知道为什么通过率只有20%,总感觉牛客的测试数据有问题。

3、将二维数组优化为一维数组加状态方程:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import java.util.Scanner; public class Main3 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNextInt()) { //总钱数 int N = sc.nextInt(); //总物品数 int M = sc.nextInt(); //二维数组,第i行表示第i个物品的价值,列:0表示主键,1表示附件1,2表示附件2 int[][] V = new int[M+1][3]; //二维数组,第i行表示第i个物品的重要程度,列:0表示主键,1表示附件1,2表示附件2 int[][] P = new int[M+1][3]; for (int i = 1; i <= M; i++) { int v = sc.nextInt(); int p = sc.nextInt(); int q = sc.nextInt(); if (q == 0) { V[i][0] = v; P[i][0] = p; } else { if (V[q][1]==0) { V[q][1] = v; P[q][1] = p; } else { V[q][2] = v; P[q][2] = p; } } } //记录最大价值 int[] dp = new int[N+1]; /** * 1、钱够用的时候,买不买主键 * 2、钱够用的时候,买不买主键、附件1 * 3、钱够用的时候,买不买主键、附件2 * 4、钱够用的时候,买不买主键、附件1、附件2 * 5、钱不够用的时候,只买前i-1件商品 */ for (int i = 1; i <= M; i++) for (int j = N; j >= 10; j-=10) { if (j >= V[i][0]) dp[j] = Math.max(dp[j], dp[j-V[i][0]]+V[i][0]*P[i][0]); if (j >= V[i][0]+V[i][1]) dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][1]]+V[i][0]*P[i][0]+V[i][1]*P[i][1]); if (j >= V[i][0]+V[i][2]) dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][2]]+V[i][0]*P[i][0]+V[i][2]*P[i][2]); if (j >= V[i][0]+V[i][1]+V[i][2]) dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][1]-V[i][2]]+V[i][0]*P[i][0]+V[i][1]*P[i][1]+V[i][2]*P[i][2]); } System.out.println(dp[N]); } } }

优化为一维数组后,通过率为100%,所以还是不清楚问题在哪儿,思路相同,一个对了,一个不对。

最后

以上就是霸气板栗最近收集整理的关于华为机试练习_16:购物单(有依赖的背包问题)的全部内容,更多相关华为机试练习_16:购物单(有依赖内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(72)

评论列表共有 0 条评论

立即
投稿
返回
顶部