勉強会課題①解答
- 2. 解答
function move($num, $from, $to)
{
1. if ($num > 1) {
2. $rest = getRest($from, $to);
3. move($num - 1, $from, $rest);
4. move(1, $from, $to);
5. move($num - 1, $rest, $to);
6. } else {
7. printText($from, $to);
8. }
}
- 3. 解説
n枚の円盤を(A) から(B)に動かす場合
1. 一番大きい円盤を除いたn-1枚を(A)から(C)に移動 → 3
行目
2. 一番大きい円盤を(A)から(B)に移動 → 4行目
3. 一番大きい円盤を除いたn-1枚を(C)から(B)に移動 → 5
行目
- 4. 0
n-1枚(n>1)
・
・
・
S(n-1)
3行目
・
・
・
S(n-1)+1 4行目
・
・
・
S(n-1)+1+S(n-1) 5行目
=2*S(n-1)+1 ・
・
・
- 5. 解説
n枚の円盤を(A) から(B)に動かす場合、
1. 一番大きい円盤を除いたn-1枚を(A)から(C)に移動
2. 一番大きい円盤を(A)から(B)に移動
3. 一番大きい円盤を除いたn-1枚を(C)から(B)に移動
n-1枚の円盤を(A) から(C)に動かす場合
1. 一番大きい円盤を除いたn-2枚を(A)から(B)に移動
2. 一番大きい円盤を(A)から(C)に移動
3. 一番大きい円盤を除いたn-2枚を(B)から(C)に移動
n-2枚の円盤を(A) から(B)に動かす場合
1. 一番大きい円盤を除いたn-3枚を(A)から(C)に移動
2. 一番大きい円盤を(A)から(B)に移動
3. 一番大きい円盤を除いたn-3枚を(C)から(B)に移動
n-2枚の円盤を(A) から(B)に動かす場合
・・・
- 6. 解説
n枚の円盤を(A) から(B)に動かす場合、
1. 一番大きい円盤を除いたn-1枚を(A)から(C)に移動
1. 一番大きい円盤を除いたn-2枚を(A)から(B)に移動
1. 一番大きい円盤を除いたn-3枚を(A)から(C)に移動
1. ・・・
2. 一番大きい円盤を(A)から(B)に移動
3. 一番大きい円盤を除いたn-3枚を(C)から(B)に移動
2. 一番大きい円盤を(A)から(C)に移動
3. 一番大きい円盤を除いたn-2枚を(B)から(C)に移動
2. 一番大きい円盤を(A)から(B)に移動
3. 一番大きい円盤を除いたn-1枚を(C)から(B)に移動
- 7. 解説
n枚の円盤を(A) から(B)に動かす場合
1. 一番大きい円盤を除いたn-1枚を(A)から(C)に移動
2. 一番大きい円盤を(A)から(B)に移動
3. 一番大きい円盤を除いたn-1枚を(C)から(B)に移動
3つの円盤のハノイの塔で考える
最初の呼び出し・・・move(3, ‘左’, ‘右’);
n = 3、A=左、B=右、C=中央
3枚の円盤を左から右に動かす場合
1. 一番大きい円盤を除いた3-1枚を左から中央に移動
2. 一番大きい円盤を左から右に移動
3. 一番大きい円盤を除いた3-1枚を中央から右に移動
- 8. 解説
3枚の円盤を左から右に動かす場合
一番大きい円盤を除いた2枚を左から中央に移動
1. 1枚を左から右へ移動
2. 1枚を左から中央へ移動
3. 1枚を右から中央へ移動
一番大きい円盤を左から右に移動
4. 1枚を左から右へ移動
一番大きい円盤を除いた2枚を中央から右に移動
5. 1枚を中央から左へ移動
6. 1枚を中央から右へ移動
7. 1枚を左から右へ移動
- 9. 解説
move(3, ‘左’, ‘右’);
if (3 > 1)
$rest = getRest(‘左’, ‘右’); //$rest = ‘中央’
move(3 - 1, ‘左’, ‘中央’);
if (2 > 1)
$rest = getRest(‘左’, ‘中央’); //$rest = ‘右’
move(2 - 1, ‘左’, ‘右’);
else
printText(‘左’, ‘右’); // 1. 左から右
move(1, ‘左’, ‘中央’);
else
printText(‘左’, ‘中央’); // 2. 左から中央
move(2 - 1, ‘右’, ‘中央’);
else
printText(‘右’, ‘中央’); // 3. 右から中央
move(1, ‘左’, ‘右’);
else
printText(‘左’, ‘右’); // 4. 左から中央
move(3 - 1, ‘中央’, ‘右’);
if (2 > 1)
$rest = getRest(‘中央’, ‘右’); //$rest = ‘左’
move(2 - 1, ‘中央’, ‘左’);
else
printText(‘中央’, ‘左’); // 5. 中央から左
move(1, ‘中央’, ‘右’);
else
printText(‘中央’, ‘右’); // 6. 左から中央
move(2 - 1, ‘左’, ‘右’);
else
printText(‘左’, ‘右’); // 7. 右から中央
- 10. 解説
アルゴリズムをいかに忠実に実現できるかが重要
再帰で書けるかどうかではなく、実現方法の1つとして再
帰を選ぶという流れが大事
実装の段階でアルゴリズムを疑わない
実装しながら考えるとぐちゃぐちゃになる
アルゴリズムを考える際にはレイヤーを意識するこ
とが重要
今回の例では、N枚を動かす場合にN-1枚の動かし方は既
知であるという考え方
レイヤーの粒度は問題によって様々
- 11. ちなみに
再帰プログラムはメモリーの消費率が高い
深さによって覚えておくものが増えるので
一般的なループでは回数によって変化しない
再帰で書けるものはループでも書ける
場合によっては相当複雑になる
ハノイの塔では異なるアルゴリズムを用いればループも可能
再帰には必ず終了条件がいる
- 12. ループで書いてみた
アルゴリズム
いちばん小さい円盤とそれ以外の円盤を交互に動かす
いちばん小さい円盤は常にB→C→A→B(円盤の数が偶数
の場合)またはC→B→A→C(円盤の数が奇数の場合)の順
に動かす
いちばん小さな円盤以外の円盤を動かす場面では、動か
せる方法は1通りしかない