1
+ '''
2
+ suppose you are trying to build a very tall tower. you have a collection of blocks to make your tower out of.
3
+ For each block type, you are given the numbers of blocks you have of that type, its weight, and the max. weight
4
+ that block can support above it and including itself. suppose for now that all blocks have the same height(1 meter).
5
+ what's the tallest tower you can construct by stacking these blocks?
6
+
7
+ Example input, with each row representing a block type of format: number of blocks, weight, max support weight:
8
+ [ [1, 1, 1], [100, 3, 100], [10, 2, 10]]
9
+ Example output: 35
10
+ for this sample problem, the best solution is to stack the single (1,1) block on top, then 4 of (2,10) blocks under it,
11
+ giving a total weight of 9; we can then stack 30 more (3, 100) blocks at the base.
12
+
13
+
14
+ 思路: dp
15
+ dp[i][j]表示使用前i种砖块 总重量为j时的最大高度
16
+ dp[i][j]可以由两种方式转移得来
17
+ 1. dp[i-1][j]:不使用第i块砖
18
+ 2. dp[i-1][j-k*weight[i]] for k:1,2,...count (当前砖可以用1,2,...count块)
19
+ 两者取一个max 就是dp[i][j]
20
+ '''
21
+ from typing import List
22
+
23
+ def max_tower_height (blocks : List [List [int ]]) -> int :
24
+ # 按承重能力(max_support)从小到大排序
25
+ blocks .sort (key = lambda x : x [2 ])
26
+
27
+ n = len (blocks )
28
+ # 所有blocks加在一起的总重量之和 是理论上dp[i][j]的j那一维的最大值
29
+ max_weight = sum (block [0 ] * block [1 ] for block in blocks )
30
+
31
+ # 初始化dp数组,dp[i][j]表示使用前i种砖块,总重量为j时的最大高度
32
+ dp = [[0 ] * (max_weight + 1 ) for _ in range (n + 1 )]
33
+
34
+ for i in range (1 , n + 1 ):
35
+ count , weight , max_support = blocks [i - 1 ]
36
+ for j in range (max_weight + 1 ):
37
+ # 不使用当前砖块
38
+ dp [i ][j ] = dp [i - 1 ][j ]
39
+
40
+ # 尝试使用当前砖块
41
+ for k in range (1 , count + 1 ):
42
+ if j >= k * weight and j <= max_support :
43
+ dp [i ][j ] = max (dp [i ][j ], dp [i - 1 ][j - k * weight ] + k )
44
+
45
+ # 返回所有可能总重量中的最大高度
46
+ return max (dp [n ])
47
+
48
+ # 测试用例
49
+ blocks1 = [[1 , 1 , 1 ], [100 , 3 , 100 ], [10 , 2 , 10 ]]
50
+ result1 = max_tower_height (blocks1 )
51
+ print (f"最大高度: { result1 } " )
52
+
53
+ blocks2 = [[4 , 1 , 10 ], [1 , 9 , 9 ], [4 , 2 , 18 ]]
54
+ result2 = max_tower_height (blocks2 )
55
+ print (f"最大高度: { result2 } " )
56
+
57
+
58
+ # followup: 如果每块砖的高度不一样
59
+ # 还是按照承重能力从小到大排序
60
+ def max_tower_height_w (blocks ):
61
+ # 按承重能力从小到大排序
62
+ blocks .sort (key = lambda x : x [2 ])
63
+
64
+ n = len (blocks )
65
+ max_weight = max (block [2 ] for block in blocks )
66
+
67
+ # 初始化dp数组
68
+ dp = [[0 ] * (max_weight + 1 ) for _ in range (n + 1 )]
69
+
70
+ for i in range (1 , n + 1 ):
71
+ count , weight , support , height = blocks [i - 1 ]
72
+ for w in range (max_weight + 1 ):
73
+ dp [i ][w ] = dp [i - 1 ][w ] # 不使用当前块
74
+
75
+ # 尝试使用当前砖块 枚举可能用多少块当前砖
76
+ for k in range (1 , count + 1 ):
77
+ if k * weight <= w and w <= support :
78
+ dp [i ][w ] = max (dp [i ][w ], dp [i - 1 ][w - k * weight ] + k * height )
79
+
80
+ return dp [n ][max_weight ]
81
+
82
+ # 测试样例
83
+ blocks = [[1 , 1 , 1 , 2 ], [100 , 3 , 100 , 1 ], [10 , 2 , 10 , 3 ]] # 答案是45 用5个blocks[2] 用30个blocks[1] 不用blocks[0]
84
+ result = max_tower_height_w (blocks )
85
+ print (f"能建造的最高塔楼高度为: { result } " )
86
+
87
+ '''
88
+ def dfs(weight:int, index:int, blocks:List[List[int]], dp:List[List[int]]) -> int:
89
+ # 基本情况:当没有更多砖块可用时
90
+ if index == len(blocks):
91
+ return 0
92
+
93
+ # 如果已经计算过这种情况,直接返回结果
94
+ if dp[weight][index] != -1:
95
+ return dp[weight][index]
96
+
97
+ # 不使用当前砖块
98
+ result = dfs(weight, index + 1, blocks, dp)
99
+
100
+ count, block_weight, max_support = blocks[index]
101
+
102
+ # 尝试使用当前砖块
103
+ if weight + block_weight <= max_support:
104
+ for i in range(1, count + 1):
105
+ if weight + i * block_weight > max_support:
106
+ break
107
+ result = max(result, i + dfs(weight + i * block_weight, index + 1, blocks, dp))
108
+
109
+ # 存储结果
110
+ dp[weight][index] = result
111
+ return result
112
+
113
+ def max_tower_height(blocks: List[List[int]]) -> int:
114
+ # 按重量升序排序
115
+ blocks.sort(key=lambda x: x[2])
116
+
117
+ n = len(blocks)
118
+ max_weight = sum(block[0] * block[1] for block in blocks)
119
+
120
+ # 初始化dp数组
121
+ dp = [[-1] * n for _ in range(max_weight + 1)]
122
+
123
+ return dfs(0, 0, blocks, dp)
124
+
125
+ # 测试用例
126
+ blocks = [[1, 1, 1], [100, 3, 100], [10, 2, 10]]
127
+ result = max_tower_height(blocks)
128
+ print(f"max height: {result}")
129
+
130
+ '''
0 commit comments