放置盒子

123 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

放置盒子

有一个立方体房间,其长度、宽度和高度都等于 n 个单位。请你在房间里放置 n 个盒子,每个盒子都是一个单位边长的立方体。放置规则如下:

  • 你可以把盒子放在地板上的任何地方。
  • 如果盒子 x 需要放置在盒子 y 的顶部,那么盒子 y 竖直的四个侧面都 必须 与另一个盒子或墙相邻。

给你一个整数 n ,返回接触地面的盒子的 最少 可能数量

示例 1:

输入: n = 3
输出: 3
解释: 上图是 3 个盒子的摆放位置。
这些盒子放在房间的一角,对应左侧位置。

示例 2:

输入: n = 4
输出: 3
解释: 上图是 3 个盒子的摆放位置。
这些盒子放在房间的一角,对应左侧位置。

示例 3:

输入: n = 10
输出: 6
解释: 上图是 10 个盒子的摆放位置。
这些盒子放在房间的一角,对应后方位置。

思路

要求最少的底面积。

首先,要明确一点的是,当前底面积为k,可以容纳多少个矩形?

这一点可能不是很好算,但是,可以发现,肯定是靠墙角堆积是最优的,只用考虑两个面。

在这个的基础上,观察一下添加底层一排矩形这个行为可以增加多少个呢?

可以发现,若是底层增加了k个矩形,那么上层可以增加k-1个矩形,对于每一层来说,都有这个规律。

那么,若是底面积增加了k,则总体矩形个数增加 k×(k+1)2\frac{k \times (k + 1) } {2}

限制:每一层必须按照按墙角对齐码放满的情况下(最优情况)

每一层码放满的情况下,底面积增加方式为 1, 3, 6, 10, ...

也就是说,第k次增加底面积的是k,总体增加 i=1ki\sum_{i=1}^k i个矩形

总共所以的矩形个数为:i=1nj=1ij\sum_{i=1}^{n}\sum_{j=1}^i j

用打表的方式大概看一下范围增长速度:

vector<long long> cur, sum;
cur.push_back(1), sum.push_back(1);
for (int i = 2; i <= 2000; i ++) {
    cur.push_back(cur.back() + i);
    sum.push_back(sum.back() + cur.back());
}

发现2000以内完全够用,所以,可以直接进行递推出大于n个矩形的那一个底面积

然后在慢慢逼近。

代码

class Solution {
public:
    int minimumBoxes(int n) {
        int cur = 1, sum = 1, i = 1;
        for (; n > sum; ) { 
            i ++;
            cur += i;
            sum += cur;
        }
        if (n == sum) return cur;
        n -= sum - cur;
        int k = 0;
        while (++ k) 
            if (n <= (k * (k + 1) / 2)) 
                return cur - i + k;
        return 114514;
    }
};