E - 荷物の積み込み / Loading Cargo 解説 by admin
GPT 5.2 High概要
各箱の「重さ \(W_i\)」と「耐荷重 \(D_i\)」から、潰れないように縦に積める箱の個数の最大値を求めます。
結論として、ある順で箱を見ていき「入れる/無理なら一番重い箱を捨てる」を繰り返す貪欲法で最大個数を求められます。
考察
重要な観察:条件は「上にある総重量」で決まる
箱を下から順に並べたとき、ある箱 \(i\) が潰れない条件は
- 「その箱より上にある箱の重さ合計」\(\le D_i\)
です。これを少し見方を変えると、箱 \(i\) 自身の重さも含めた「その箱より上+自分」までの総重量を \(T\) とすると
- \(T \le W_i + D_i\)
となります。ここで \(W_i + D_i\) は「その箱が支えられる最大の総重量(自分込み)」なので、これを 強さ(strength) と呼びます。
つまり、下から順に見たとき「ここまでに積んだ総重量 \(T\) が、各箱の強さ \(S_i=W_i+D_i\) を超えない」ようにできればOKです。
素朴な方法が難しい理由
- どの箱を選ぶか(部分集合)と、どの順で積むか(順列)の両方を最適化する必要があります。
- 全探索は当然不可能で、DPも「総重量」が \(10^9\) なので重さDPは使えません。
- \(N \le 2\times 10^5\) のため、\(O(N^2)\) のような方法も間に合いません。
解決の方針:並べる順を固定して貪欲に「個数最大」を狙う
箱を 強さ \(S_i=W_i+D_i\) の昇順 に並べて考えます。この順で見ていくと、
- いままで選んだ箱たちの総重量を \(T\) とする
- 新しい箱(強さ \(S\)、重さ \(W\))を追加して \(T+W \le S\) なら安全に「どこかに」積める可能性が保たれる
もし \(T+W > S\) となってしまったら、「今の集合の中から何かを捨てないと、この強さ \(S\) の箱を最下層側に含むような積み方は不可能」です。
個数を最大化したいので、捨てるなら総重量を一番減らせる 最も重い箱 を捨てるのが得です。
この「追加してダメなら最重箱を捨てる」を繰り返すと、各時点で - その時点までに見た箱だけで作れる「最大個数の集合」 を保ちながら進められます。
アルゴリズム
- 各箱について強さ \(S_i = W_i + D_i\) を計算し、ペア \((S_i, W_i)\) を作る。
- \((S_i)\) の昇順にソートする。
- いま選んでいる箱の総重量
totalと、選んでいる箱の重さを管理するヒープを用意する。- 「最も重い箱」をすぐ取り出したいので 最大ヒープ が欲しい(Pythonは最小ヒープなので負の値で代用)。
- ソート順に箱を1つずつ処理:
- とりあえず箱を採用:
total += w、ヒープに-wを追加 - もし
total > Sなら条件違反なので、ヒープから「最も重い箱」を1つ捨てる(totalからその重さ分を引く)
- とりあえず箱を採用:
- 最後にヒープに残った個数が答え。
直感的な例
強さの小さい箱(\(W+D\) が小さい箱)は「上にあまり載せられない」ので下に置きにくく、先に処理して条件を守る必要があります。
途中で総重量がオーバーしたら、重い箱を捨てると総重量が一番減り、残せる箱数が増えやすい、という発想です。
計算量
- 時間計算量: \(O(N \log N)\)(ソート \(O(N\log N)\) + 各箱でヒープ操作 \(O(\log N)\))
- 空間計算量: \(O(N)\)(箱配列とヒープ)
実装のポイント
強さは \(S_i = W_i + D_i\)。この値で昇順ソートするのが核心です。
Pythonの
heapqは最小ヒープなので、最大値(最重箱)を取り出すために-wを入れます。total > Sになったときに捨てるのは「必ず1個でよい」ことに注意:
今回は「1個追加したことで超えた」状態なので、最大の重さを1つ捨てればtotalは最も大きく減り、以後の処理に最適です。ソースコード
import sys
import heapq
def main():
input = sys.stdin.readline
N = int(input())
boxes = []
for _ in range(N):
w, d = map(int, input().split())
boxes.append((w + d, w)) # (strength, weight)
boxes.sort() # by strength ascending
total = 0
heap = [] # max-heap by weight via negative
for s, w in boxes:
total += w
heapq.heappush(heap, -w)
if total > s:
total += heapq.heappop(heap) # subtract largest weight
print(len(heap))
if __name__ == "__main__":
main()
この解説は gpt-5.2-high によって生成されました。
投稿日時:
最終更新: