Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonでk回の移動後にインデックス0へ戻る経路の数を求めるプログラム


問題概要

長さ n のリストの位置 0(インデックス 0)からスタートします。各ステップでは、「右に 1 つ進む」「左に 1 つ戻る(リストの範囲外には出られない)」「その場にとどまる」のいずれかの操作を選べます。ここで、ちょうど k ステップを使って再びインデックス 0 に戻ってくる一意な移動経路(ウォーク)の総数を求めるのがこの問題です。答えが非常に大きくなる可能性があるため、10^9 + 7 で割った余りを返します。

たとえば、入力が n = 7、k = 4 の場合、出力は 9 になります。条件を満たす操作列は次の 9 通りです。

  • [右、右、左、左]
  • [右、左、右、左]
  • [待機、待機、待機、待機]
  • [右、左、待機、待機]
  • [待機、待機、右、左]
  • [右、待機、待機、左]
  • [右、待機、左、待機]
  • [待機、右、左、待機]
  • [待機、右、待機、左]

解き方のアプローチ

この問題は、再帰と動的計画法(DP)の考え方を組み合わせることで解けます。手順は以下のとおりです。

  • m := 10^9 + 7(剰余を取るための定数)
  • N := リストの長さ
  • dp(i, jumps) という関数を定義する。i は現在位置、jumps は残りのステップ数
  • jumps が 0 のとき、i が 0 なら 1、そうでなければ 0 を返す
  • count := dp(i, jumps − 1)(その場にとどまるケース)
  • i ≥ 0 の場合、count := count + dp(i + 1, jumps − 1)(右へ移動するケース)
  • i ≤ N − 1 の場合、count := count + dp(i − 1, jumps − 1)(左へ移動するケース)
  • count を返す
  • メイン処理では dp(0, k) mod m を返す

それでは、実際の実装を見て理解を深めましょう。

実装例(Python)

class Solution:
   def solve(self, length, n):
      MOD = 10 ** 9 + 7
      N = length

      def dp(i, jumps):
         if jumps == 0:
            return +(i == 0)

         count = dp(i, jumps - 1)
         if i >= 0:
            count += dp(i + 1, jumps - 1)
         if i <= N - 1:
            count += dp(i - 1, jumps - 1)
         return count
      return dp(0, n) % MOD    
ob = Solution()
n = 7
k = 4
print(ob.solve(n, k))

入力

7, 4

出力

9

補足:計算量について

上記の実装は素朴な再帰のみで構成されているため、ステップ数 k が大きくなると計算量が指数的に増大します。functools.lru_cache などを使ってメモ化を行えば、状態数は「現在位置 × 残りステップ数」に抑えられるため、大幅な高速化が可能です。競技プログラミングなどで大きな入力を扱う場合は、メモ化の導入を検討するとよいでしょう。

  1. Pythonで素数を判定するプログラムの書き方を徹底解説

    はじめに この記事では、「与えられた数値が素数かどうかを判定する」という問題に対する解決策を、Pythonのコード例とともにわかりやすく解説します。 問題の概要 問題設定:ある数値が与えられたとき、その数が素数であるかどうかを判定するプログラムを作成します。 まず「素数」の定義をおさらいしましょう。1より大きい正の整数のうち、1とその数自身以外に約数を持たない数を素数(そすう)と呼びます。たとえば、2、3、5、7などはそれ以外の約数を持たないため、素数です。 プログラムの考え方 今回作成するプログラムでは、入力された数値が素数かどうかを以下の手順で判定します。 1以下の数値は素数ではない

  2. Pythonでアームストロング数を判定するプログラムの書き方

    この記事では、与えられた整数が「アームストロング数(Armstrong number)」であるかどうかを判定するための考え方と、Pythonによる具体的な実装方法を解説します。 問題の定義 整数 n が与えられたとき、その整数がアームストロング数であるかどうかを判定することを目標とします。 アームストロング数とは? n 桁の正の整数 abcd… が次の条件を満たすとき、この数は「n 次(オーダー n)のアームストロング数」と呼ばれます。 abcd... = a^n + b^n + c^n + d^n + … つまり、各桁の数字を「桁数乗」した値の総和が、元の数と一致するかを確認す