LeetCode 12.10 每日一题 堆叠正方体的最大高度
算法:贪心 + DP
-
首先要注意到题目条件说的,如果一个长方体(长宽高为 a 1 , b 1 , c 1 a_1, \space b_1, \space c_1 a1, b1, c1)可以放在另一个长方体(长宽高为 a 2 , b 2 , c 2 a_2, \space b_2, \space c_2 a2, b2, c2)上方,那就意味着 a 1 ⩽ a 2 , b 1 ⩽ b 2 , c 1 ⩽ c 2 (1) a_1 \leqslant a_2, \space b_1 \leqslant b_2, \space c_1 \leqslant c_2 \tag 1 a1⩽a2, b1⩽b2, c1⩽c2(1) 那么我们可以有一个合理猜测 —— 将各个长方体最长的边作为垒起来的高,这样就会得到最优结果。
-
我们先来证明一个性质,就是两个长方体,已经满足了式子 ( 1 ) (1) (1),现将两个长方体的长宽高重新按升序排序,仍然满足式子 ( 1 ) (1) (1)。设当前已经将 a 1 , b 1 , c 1 a_1, \space b_1, \space c_1 a1, b1, c1 排好序,即 a 1 ⩽ b 1 ⩽ c 1 (2) a_1 \leqslant b_1 \leqslant c_1 \tag 2 a1⩽b1⩽c1(2) 若此时 a 2 , b 2 , c 2 a_2, \space b_2, \space c_2 a2, b2, c2 已经是升序,那肯定成立。若其中 b 2 ⩾ c 2 b_2 \geqslant c_2 b2⩾c2,则调换其顺序,对应关系如下: a 1 b 1 c 1 a_1 \space \space b_1 \space \space c_1 a1 b1 c1 a 2 c 2 b 2 a_2 \space \space c_2 \space \space b_2 a2 c2 b2 现由 c 2 ⩾ c 1 ⩾ b 1 , b 2 ⩾ c 2 ⩾ c 1 及 式 子 ( 2 ) c_2 \geqslant c_1 \geqslant b_1, \space b_2 \geqslant c_2 \geqslant c_1 \space 及 \space 式子 \space (2) c2⩾c1⩾b1, b2⩾c2⩾c1 及 式子 (2) 得式子 ( 1 ) (1) (1) 仍成立,若 a 2 ⩾ b 2 a_2 \geqslant b_2 a2⩾b2,则继续如法炮制。所以该性质成立。
-
接着是贪心的证明。设贪心解答案为 r e s res res,最优解答案为 a n s ans ans,那么首先一定有 r e s ⩽ a n s res \leqslant ans res⩽ans。接下来证明 r e s ⩾ a n s res \geqslant ans res⩾ans。不妨设最优解里存在一个不是以某个长方体的最长边为高的,那么就一定是以更短的或是一样长的另一条边作为高,由于最优解也是一个,所以一定满足 a 1 ⩽ a 2 , b 1 ⩽ b 2 , c 1 ⩽ c 2 a_1 \leqslant a_2, \space b_1 \leqslant b_2, \space c_1 \leqslant c_2 a1⩽a2, b1⩽b2, c1⩽c2 的要求,此时将这个与贪心解不一样的地方转化为贪心解,由上述 2. 2. 2. 的证明,此时仍然满足式子 ( 1 ) (1) (1) 的要求,而得到的结果一定不会变差,所以有 r e s ⩾ a n s res \geqslant ans res⩾ans,综上有 a n s = r e s ans = res ans=res,也就是 贪心解即是最优解。
-
所以我们可以将每个长方体的长宽高重新按升序排序;而对外层,也就是所有长方体,我们可以升序排,也可以逆序排。如果是升序,那相当于求一个最长上升子序列,也就是先从最顶层开始堆方块;如果是降序,那相当于求一个最长下降子序列,也就是先从最底层开始堆方块。这里采用升序。
-
设 f ( i ) f(i) f(i) 表示以第 i i i 个长方体作为底的最大堆叠高度,则就有 f ( i ) = m a x ( f ( i ) , f ( j ) + h e i g h t [ i ] ) f(i) = max(f(i), f(j) + height[i]) f(i)=max(f(i),f(j)+height[i]), 0 ⩽ j < i 0 \leqslant j \lt i 0⩽j<i,即从前 i − 1 i - 1 i−1 个长方体中选择一个长方体能够满足条件,接在 i i i 上,由于当前的 h e i g h t [ i ] height[i] height[i] 是定值,所以只需要 f ( j ) f(j) f(j) 最大。
C ++ 代码
#define all(x) x.begin(), x.end()
class Solution {
public:
int maxHeight(vector<vector<int>>& c) {
int n = c.size();
for (auto &x: c) sort(all(x));
sort(all(c));
vector<int> f(n);
int res = 0;
for (int i = 0; i < n; i ++ ) {
f[i] = c[i][2];
for (int j = 0; j < i; j ++ )
if (c[j][1] <= c[i][1] && c[j][2] <= c[i][2])
f[i] = max(f[i], f[j] + c[i][2]);
res = max(res, f[i]);
}
return res;
}
};