Files
hello-algo/ja/docs/chapter_divide_and_conquer/hanota_problem.md
T
Yudong Jin 7257641e0e Retranslate the complete Japanese online edition from Chinese (#2008)
* Retranslate the complete Japanese online edition from Chinese

* Fit Japanese homepage labels and localize heading permalinks

* Point Japanese contribution instructions to the Japanese preview

* Replace locale conditionals with multilingual UI tables
2026-10-30 02:12:26 +08:00

5.9 KiB
Raw Blame History

ハノイの塔の問題

マージソートと二分木の構築では、元の問題をそれぞれ半分の大きさの二つの部分問題に分解しました。一方、ハノイの塔の問題では、別の分解戦略を使います。

!!! question

3 本の柱 `A`、`B`、`C` が与えられます。初期状態では、柱 `A` に $n$ 枚の円盤があり、上から下へ、小さい順に重なっています。この $n$ 枚を、元の順序を保ったまま柱 `C` に移してください(下図参照)。円盤を動かす際は、次の規則に従います。

1. 円盤は柱の一番上から取り出し、別の柱の一番上に置くことしかできません。
2. 一度に動かせる円盤は 1 枚だけです。
3. 小さな円盤は、常に大きな円盤の上に置かなければなりません。

ハノイの塔の問題の例

大きさ i のハノイの塔の問題を f(i) と表します。たとえば f(3) は、3 枚の円盤を A から C に移す問題です。

基本的な場合を考える

下図のように、問題 $f(1)$、つまり円盤が 1 枚だけの場合は、その円盤を A から C に直接移せば完了です。

=== "<1>" 大きさ 1 の問題の解

=== "<2>" 円盤が 1 枚のハノイの塔:手順 2

下図のように、問題 $f(2)$、つまり円盤が 2 枚の場合は、小さな円盤を常に大きな円盤の上に置くため、B を利用して移す必要があります。

  1. まず、上にある小さな円盤を A から B に移します。
  2. 次に、大きな円盤を A から C に移します。
  3. 最後に、小さな円盤を B から C に移します。

=== "<1>" 大きさ 2 の問題の解

=== "<2>" 円盤が 2 枚のハノイの塔:手順 2

=== "<3>" 円盤が 2 枚のハノイの塔:手順 3

=== "<4>" 円盤が 2 枚のハノイの塔:手順 4

問題 f(2) を解く手順は、B を使って 2 枚の円盤を A から C に移すこととまとめられます。このとき、C を目的の柱、B を補助の柱と呼びます。

部分問題への分解

問題 $f(3)$、つまり円盤が 3 枚の場合は、少し複雑になります。

f(1) と f(2) の解はわかっているので、分割統治の観点から、A の上側の 2 枚を一つのまとまりとみなし、下図の手順を実行します。これで 3 枚の円盤を A から C に移せます。

  1. B を目的の柱、C を補助の柱として、2 枚の円盤を A から B に移します。
  2. A に残った 1 枚を、A から C に直接移します。
  3. C を目的の柱、A を補助の柱として、2 枚の円盤を B から C に移します。

=== "<1>" 大きさ 3 の問題の解

=== "<2>" 円盤が 3 枚のハノイの塔:手順 2

=== "<3>" 円盤が 3 枚のハノイの塔:手順 3

=== "<4>" 円盤が 3 枚のハノイの塔:手順 4

本質的には、問題 f(3) を、二つの部分問題 f(2) と、一つの部分問題 f(1) に分割しています。この三つを順に解けば、元の問題も解けます。部分問題は独立しており、解を統合できるということです。

ここまでの考察から、下図のように、ハノイの塔を解く分割統治戦略をまとめられます。元の問題 f(n) を、二つの部分問題 f(n-1) と一つの部分問題 f(1) に分割し、次の順で解きます。

  1. C を使って n-1 枚の円盤を A から B に移します。
  2. 残りの 1 枚を A から C に直接移します。
  3. A を使って n-1 枚の円盤を B から C に移します。

二つの部分問題 f(n-1) は、同じ方法で再帰的に分割でき、最小の部分問題 f(1) に到達するまで続けます。f(1) の解はわかっており、1 回移動するだけです。

ハノイの塔を解く分割統治戦略

コードの実装

コードでは、再帰関数 dfs(i, src, buf, tar) を定義します。この関数は、柱 src の上側にある i 枚の円盤を、補助の柱 buf を使って目的の柱 tar に移します。

[file]{hanota}-[class]{}-[func]{solve_hanota}

下図のように、ハノイの塔の問題は高さ n の再帰木をなします。各ノードは一つの部分問題を表し、1 回の dfs() の呼び出しに対応します。したがって、時間計算量は $O(2^n)$、空間計算量は O(n) です。

ハノイの塔の問題の再帰木

!!! quote

ハノイの塔の問題は、古い伝説に由来します。古代インドのある寺院に、3 本の高いダイヤモンドの柱と、大きさの異なる $64$ 枚の金の円盤がありました。僧侶たちは円盤を動かし続け、最後の円盤を正しい位置に置いた瞬間に、この世界が終わると信じていました。

しかし、仮に毎秒 1 回ずつ動かしても、合計で約 $2^{64} \approx 1.84×10^{19}$ 秒、すなわち約 $5850$ 億年かかります。これは現在推定されている宇宙の年齢をはるかに超えます。したがって、この伝説が本当だとしても、世界の終わりを心配する必要はなさそうです。