ハノイの塔 解説

13
ハノイの塔 解説 ギノ株式会社 吉岡 恒夫

Upload: paiza

Post on 20-Jul-2015

1.887 views

Category:

Software


2 download

TRANSCRIPT

ハノイの塔 解説ギノ株式会社 吉岡 恒夫

問題ハノイの塔

• 問題: https://paiza.jp/learning/hanoi

• 3つの杭がある。

• 杭には円盤が置かれている。

• ある円盤の下には、大きい円盤しか置けない。

• 一番左の杭に積まれたn段の円盤を一番右に動かす。

• 最短の方法で移動した場合のt手目の状態を出力

• 1≤n≤16 0<t≤2^n-1

解法

• 一番右の杭について考えると、一番大きい円盤から順番に一番右の杭に置く必要がある。

• まず、一番大きい杭について考える。

• 一番大きい円盤を動かすためには、大きい円盤の上の円盤を真ん中の円盤に動かす必要がある。

解法

解法• 関数定義: hanoi(n, 移動元、移動先、あまり)n段の円盤を移動元から移動先に移動する関数として定義する。

• hanoi(n-1、移動元、あまり、移動先)n-1段を移動元からあまりに移動する。

• 大きさnの円盤を異動元から移動先に移動する。

• hanoi(n-1, あまり、移動先、異動元) n-1段をあまりから移動先に移動する。

コード

N,  @T  =  gets.split.map(&:to_i)      @t=0  @plates  =  [  N.downto(1).to_a,[],[]  ]      def  show          (0..2).each{|i|                  if  @plates[i].size  ==  0                          puts  "-­‐"                  else                          puts  @plates[i].join("  ")                  end          }  end      def  move_one(n,  from,  to)          plate  =  @plates[from].pop          @plates[to].push(plate)          @t  +=  1          if  @t  ==  @T                  show                exit          end  end          def  hanoi(n,  from,  to,  other)          if  n  ==  0                  return          end          hanoi(n-­‐1,  from,  other,  to)          move_one(n,  from,  to)          hanoi(n-­‐1,  other,  to,  from)  end      hanoi(N,  0,  2,  1)

プレートを動かす回数• hanoi(n): n段の円盤を移動させるのに必要な回数

• hanoi(n) = hanoi(n-1) * 2 + 1

• hanoi(n)+1 = (hanoi(n-1)+1)*2

• hanoi(n)+1 = 2^n

• hanoi(n) = 2^n - 1n=16の場合、65535 => ok!

• 計算量: O(2^n)

ところで

• 本物(?)のハノイの塔は64段!

• もし n = 64なら?

• 移動回数2^64-1= 18446744073709551615(1秒に一回移動させるとして1000億年)

解法2

• nがT以下の場合、シミュレーションしなくても、動かしたことにしてしまえばいい!

コードdef  hanoi(n,  from,  to,  other)          if  n  ==  0                  return          end          if  @T  >=  @t  +  (2**n)-­‐1                  plates  =  @plates[from].pop(n)                  @plates[to].push(*plates)                  @t  +=  (2**n  -­‐  1)                  show  if  @t  ==  @T                  return          end          …

計算量

• 解法1(総当たり) O(2^n)

• 解法2(最適化後)O(n)# 各nについてhanoiは一回のみ呼ばれる