AtCoder Beginner Contest 095 C - Half and Half の解法考察 Pythonで書いてます
最近、AtCoderをボチボチやっていて、すごく書きたくなって書きました。
問題はこちら
C - Half and Half
A・・・Aピザの金額
B・・・Bピザの金額
C・・・ABピザの金額
X・・・Aピザの金額
Y・・・Aピザの金額
求めるものは最小のAピザ、Bピザの必要枚数分の金額
注意点は各ピザを多く買ってもいいってこと。
まずA+B<=2Cかどうかチェックする。A+B<=2CならABピザを買うと割高なので、ABピザは買わずにAピザ、Bピザをそれぞれ買えばよろしい。
んで、A+B>=2Cの場合、とりあえずABピザでAピザ、Bピザのうち少ない枚数の方を賄っちゃって、残りをまたABピザを買って賄うか、ABピザを買わずに、Aピザ、Bピザをそれぞれ買うのかを比較する。
なぜ少ない枚数の方をABピザで賄うかというとABピザで全てを賄わないパターンを比較対象に含めるためである。
なのでAピザ、Bピザの枚数が少ない方をチェックする。X<=Yのときは2CX+2C(Y-X)=2CY or 2CX+B(Y-X)だし、X>=Yのときは2CY+2C(X-Y)=2CX or 2CY+A(X-Y)との比較となる。
ここでY-Xについてだが、
例えば、X<=Yのとき、つまりAピザ、Bピザのうち少ない枚数がAピザのX枚の方だとしたらCを2枚、X枚買うとそれはつまり、AピザX枚とBピザX枚である。残りはBピザY枚からBピザX枚を引いたBピザの枚数Y-X枚となる。
これをコードで表すとこちらになる。
A, B, C, X, Y = map(int, input().split()) if A+B <= 2*C: print(A*X+B*Y) else: if X <= Y: print(min(2*C*Y, 2*C*X+B*(Y-X))) else: print(min(2*C*X, 2*C*Y+A*(X-Y)))
しかし、しかしだ。僕はこの問題を全探索の練習問題として紹介されて解き始めた。なので上記はやりたい解法ではなかった。
金額A,B,Cのパターン全探索すると時間がかかる。ABCXYを数式化してみよう。ABピザの枚数をZ枚として、、、
A(X-Z)+B(Y-Z)+2CZ
2CZ=AZ+BZなのでAXとBYから引いてあげれば帳尻が合う。
となるとコードはこちらになる。
A, B, C, X, Y = map(int, input().split()) ans = 2*(5000*10**5) for Z in range(10**5+1): total = A*max(X-Z, 0)+B*max(Y-Z, 0)+2*C*Z ans = min(total,ans) print(ans)
全探索のパターンを減らすには、問題の登場人物の関係性を特定して数式化する必要があるけど、そこが難しいんだよね。