本日はこちらです。前回の記事でやった問題の進化版ですね。
一応前回のnoteのリンクも貼っておきます。

前回やった問題では、カエルさんは1個先の足場と2個先の足場に飛ぶことが出来ていました。カエルさんの1ステップの可動域は2個先まででしたが、今回の問題ではそれが定まっていません。
つまり、入力ごとにカエルさんの跳躍力が高かったり低かったりするのです。あるカエルさんは1個先までしか飛べず、また別のカエルさんは10個先まで飛べてしまうみたいな感じですね。

いつもどおりコード紹介いっちゃいます。

import sys
N, K = map(int, input().split())
ashibaList = list(map(int, input().split()))
INF = 10**20
dp = [INF for _ in range(N)]
dp[0] = 0

if N <= 1:
 print(dp[0])
 exit()

jumpLimit = 0
for i in range(1, N):
 if i < K:
   jumpLimit = i
   #print (jumpLimit)
 else:
   jumpLimit = K
 for j in range(jumpLimit):
   #print ("j= " + str(j) + ", i="+str(i))
   score = abs(ashibaList[i]- ashibaList[i-j-1]) + dp[i-j-1]
   if dp[i] > score:
     dp[i] = score
print(dp[N-1])

おおまかな内容は前回と変わらないので早速細かく見ていきます。

import sys
N, K = map(int, input().split())
ashibaList = list(map(int, input().split()))
INF = 10**20
dp = [INF for _ in range(N)]
dp[0] = 0

if N <= 1:
 print(dp[0])
 exit()

見た感じ前回のコードとあまり変わりませんね。
しかし、今回の問題の入力は、前回の問題の入力よりも一つ増えており、カエルさんが何個先まで飛べるかを表す数(K)が、足場の数を表す数字(N)と同じ行にきています。なので、map関数で入力を受け取っています。便利な関数ですね。前回と同様にdpを足場の数だけ大きな数字で初期化し、dp[0]に0、足場が一つだけなら0を出力。

jumpLimit = 0
for i in range(1, N):
 if i < K:
   jumpLimit = i
   #print (jumpLimit)
 else:
   jumpLimit = K
 for j in range(jumpLimit):
   #print ("j= " + str(j) + ", i="+str(i))
   score = abs(ashibaList[i]- ashibaList[i-j-1]) + dp[i-j-1]
   if dp[i] > score:
     dp[i] = score
print(dp[N-1])

前回とコード量はほとんど変わっていないのですが、ここで何気に苦労しました。

前回は2個先の足場までしか飛べないカエルしかいなかったので、ある足場から見て一つ手前の足場と二つ手前の足場でスコアを計算すればよかったため、for j in range(2)として2回ループをするだけで良かったのです。
前回は2回ループができないashibaList[1](スタートから見て2個目の足場)に関してはfor文に入る前に処理していましたね。しかし、今回はそれが出来ません。カエルさんの跳躍力が定まっていないため、何回ループをすればいいか分からないのです。
jumpLimitはその定まっていないループ数を決定するための変数です。
jumpLimitの値を決めるためにif文で分岐していますがこれに関しては具体例を使って説明したいと思います。

例えば、2段先まで飛べるカエルがいるとします。このときK=2となりますね。for i in range(1,N):で、一番最初の i には 1 が入りますね。このとき、ashibaList[i]=スタートから2番目の足場の高さとなりますね。2番目の足場なので、この足場の前には一つだけ足場があるということになります。スタート地点となる足場ですね。手前に一つだけしか足場がないということは、2番目の足場に辿り着くための道筋は、足場1から足場2の一通りしかないですね。なので、足場2のスコアの候補は一つだけしかないです。このとき、for j in range(jumpLimit): の繰り返し数は一回だけでいいので、jumpLimitが1になるようにしたいわけです。i = 1 でもあるので、jumpLimit = i としています。
そして、次のループ i = 2 のときです。このとき、スタートから3番目の足場を見ていますね。ここでi= 2、K=2となっているため、if i < K の条件を満たせずelse文の方に分岐します。そしてjumpLimit = K つまりjumpLimit= 2となりますね。そして、このカエルに関しては可動域が2なのでこれ以降のループは全てelse文を通り、for j in range(jumpLimit): は2回ループが限度となりますね。
なので足場3のときは、足場2→足場3、足場1→足場3のスコアをチェックしdp更新、足場4のときは、足場2→足場4、足場3→足場4のスコアをチェックという流れになります。いい感じですね。

カエルが3段先まで飛べる場合も同様に足場3まではjumpLimitの回数が1ずつ上昇していき、足場4以降になるとi = 3、K=3よりi < K の条件を満たせず、else文のjumpLimit=Kとなり、jumpLimitの数は3に収束します。なのでループ回数も3に落ち着きます。

それ以降は大体前回と同じなので割愛します。

今回長々と例を挙げながら書いた部分の実装にメチャクソ時間がかかりました。頭のいい人は一瞬で導けそうなものなのですが、自分はどうにもダメです。早くコーディングする能力を身に着けたいのですが、考えることにこんなに時間を割いているようでは目標まではまだまだ遠そうです(泣)




この記事が気に入ったらサポートをしてみませんか?