リーチkまでの最小移動

Prepcastdoom:

二つの数を考えるmn、一手に使用すると、2つの新しいペアを取得することができます:

  • m+n, n
  • m, n+m

さんはintially設定してみましょうm = n = 1移動の最小数数字の対等のように少なくとも一つを見つけますk

解決策は、(すなわちリードが移動の順序がkに存在していること)があります保証されています

たとえば、次の指定されたk = 5ように、動きの最小数mに等しいまたはNであるk3

1, 1
1, 2
3, 2
3, 5

3つの移動の合計。

私はPythonで再帰を使用して解決策を考え出す必要があり、それは、大きな数の上で動作するようには思えない(つまり、10 ^ 6)

def calc(m, n, k):
    if n > k or m > k:
        return 10**6
    elif n == k or m == k:
        return 0
    else:
        return min(1+calc(m+n, n, k), 1+calc(m, m+n, k))

k = int(input())
print(calc(1, 1, k))

それは大きな数字のために働くように、どのようにしてパフォーマンスを向上させることができますか?

DarrylG:

(ヒープを使用して)優先度キューに基づく非再帰的アルゴリズム

State: (sum_, m, n, path)
    sum_ is current sum (i.e. m + n)
    m and n are the first and second numbers
    path is the sequence of (m, n) pairs to get to the current sum

各ステップで二つの可能な移動があります

  1. 合計で最初の番号を交換してください
  2. 合計することにより、第2の数を交換してください

したがって、各状態は、2つの新しい状態を生成します。米国はによって優先順位付けされています。

  1. 移動:状態の低い数字では、より高い優先順位を持っています
  2. 合計:高合計と国が高い優先順位を持っています

私たちは、優先順位によって、プロセスの状態に優先順位キュー(この場合はヒープ)を使用します。

コード

def calc1(k):
  if k < 1:
    return None, None  # No solution

  m, n, moves = 1, 1, 0
  if m == k or n == k:
    return moves, [(m, n)]

  h = []  # Priority queue (heap)

  path = [(m, n)]
  sum_ = m + n
  # Python's heapq acts as a min queue.
  # We can order thing by max by using -value rather than value
  # Thus Tuple (moves+1, -sum_, ...) prioritizes by 1) min moves, and 2) max sum
  heappush(h, (moves+1, -sum_, sum_, n, path))
  heappush(h, (moves+1, -sum_, m, sum_, path))

  while h:
    # Get state with lowest sum
    moves, sum_, m, n, path = heappop(h)

    sum_ = - sum_

    if sum_ == k:
      return moves, path  # Found solution

    if sum_ < k:
      sum_ = m + n  # new sum
      # Replace first number with sum
      heappush(h, (moves+1, -sum_, sum_, n, path + [(sum_, n)]))
      # Replace second number with sum
      heappush(h, (moves+1, -sum_, m, sum_, path + [(m, sum_)]))

    # else:
    #  so just continues since sum_ > k

  # Exhausted all options, so no solution
  return None, None

テスト

テストコード

for k in [5, 100, 1000]:
  moves, path = calc1(k)
  print(f'k: {k}, Moves: {moves}, Path: {path}')

出力

k: 5, Moves: 3, Path: [(1, 1), (2, 3), (2, 5)]
k: 100, Moves: 10, Path: [(1, 1), (2, 3), (5, 3), (8, 3), (8, 11),
                         (8, 19), (27, 19), (27, 46), (27, 73), (27, 100)]
k: 1000, Moves: 15, Path: [(1, 1), (2, 3), (5, 3), (8, 3), (8, 11),
                          (19, 11), (19, 30), (49, 30), (79, 30), (79, 109), 
                          (188, 109), (297, 109), (297, 406), (297, 703), (297, 1000)]

パフォーマンスの向上

パフォーマンスを向上させるために、2つの調整の後

  1. K = 10,000 3Xの高速化を提供するステップのパスだけの数が(を含めません
  2. 対称ペアを使用していない(K = 10、000と追加の2X提供

同じ前後に、そのような(1、2)や(2,1)であり、対称対Mの平均対Nで。
彼らは同じソリューションのステップ数を提供しますので、我々は、これらの両方にブランチには必要ありません。

改善されたコード

def calc(k):
  if k < 1:
    return None, None

  m, n, moves = 1, 1, 0
  if m == k or n == k:
    return moves

  h = []    # Priority queue (heap)

  sum_ = m + n
  heappush(h, (moves+1, -sum_, sum_, n))

  while h:
    moves, sum_, m, n = heappop(h)
    sum_ = - sum_

    if sum_ == k:
      return moves

    if sum_ < k:
      sum_ = m + n
      steps = [(sum_, n), (m, sum_)]
      heappush(h, (moves+1, -sum_, *steps[0]))
      if steps[0] != steps[-1]: # not same tuple in reverse (i.e. not symmetric)
        heappush(h, (moves+1, -sum_, *steps[1]))

演奏

Tested up to k = 100, 000 which took ~2 minutes.

おすすめ

転載: http://10.200.1.11:23101/article/api/json?id=408709&siteId=1