ABC266 D - Snuke Panic (1D) Python解答例
AtCoder Beginner Contest 266 D - Snuke Panic (1D)をPythonで解きます。
問題
問題文をAtCoderのページより引用します。
問題文
高橋君はすぬけ君たちを捕まえようとしています。
数直線上の座標
の 0,1,2,3,4 箇所に穴があり、すぬけ君たちの巣につながっています。 5 これから
匹のすぬけ君が穴から出てきます。 N 番目のすぬけ君は時刻 i に座標 T_i の穴から出てきて、大きさは X_i であることがわかっています。 A_i 高橋君は時刻
に座標 0 におり、数直線上を単位時間あたり 0 以下の速さで移動することができます。 1
すぬけ君が穴から出てきたのと同じ時刻に同じ座標に高橋君がいるとき、かつ、そのときに限り、高橋君はすぬけ君を捕まえることができます。
すぬけ君を捕まえるのにかかる時間は無視できます。高橋君が適切に行動したとき、捕まえることができるすぬけ君の大きさの合計の最大値を求めてください。
制約
1 \leq N \leq 10^5 0 < T_1 < T_2 < \ldots < T_N \leq 10^5 0 \leq X_i \leq 4 1 \leq A_i \leq 10^9 - 入力に含まれる値は全て整数である
解答例
動的計画法で解く
まず、考察を簡単にするため、高橋君の行動である「数直線状を単位時間あたり1以下の速さで移動する」を「各時刻について『左に1つ動く』『その場で待機する』『右に1つ動く』の3通りから選ぶ」と言い換えます。
高橋君がある時刻
- 時刻
に座標t - 1 にいて、1秒かけて右に移動したx - 1 - 時刻
に座標t - 1 にいて、その場で待機したx - 時刻
に座標t - 1 にいて、1秒かけて左に移動したx + 1
同時に、時刻
なんとなく動的計画法っぽく解けるような気がしてきました。
DPテーブルの定義
DPテーブルを以下のように定義します。尚、それまでに捕まえたすぬけ君の大きさの合計の最大値を「スコア」と呼ぶこととします。
初期値は以下のようにします。
また、2次元配列
DPの遷移は以下のようになります。
ただし、
解は
実装例
Pythonによる実装例を以下に示します。
from typing import *
def main():
# 入力受け取り
N: int = int(input())
T, X, A = map(list, zip(*[list(map(int, input().split())) for i in range(N)]))
# Tの最大値(シミュレートする時間の範囲を決める)
time: int = max(T)
# 2次元配列Cの準備
C: List[List[int]] = [[0] * 5 for i in range(time + 1)]
for t, x, a in zip(T, X, A):
# 時刻tに座標xにすぬけ君が現れるとき、その大きさを記録する
# 現れないなら0にする
C[t][x] = a
# DPテーブル
# 無限小は適当に負の大きい数を充てておく
dp: List[List[int]] = [[-(1 << 60)] * 5 for i in range(time + 1)]
# 高橋君は時刻0に座標0にいる
dp[0][0] = 0
# 遷移開始
for i in range(1, time + 1):
for j in range(5):
dp[i][j] = (
max(dp[i - 1][max(0, j - 1)], dp[i - 1][j], dp[i - 1][min(4, j + 1)])
+ C[i][j]
)
# 解の出力
print(max(dp[time]))
if __name__ == "__main__":
main()
実際の提出はこちら。
Discussion