このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。
ある関数から自分自身の関数を呼び出すことを再帰と言います。 これを使うと、短い記述で複雑な問題を解くことができます。
ある問題を解く際に、その問題を同じ性質を持つ小さい部分に分解できるとし ます。 すると、その問題を解く関数 solve は再帰処理を使うと次のように書くこと ができます。
int solve(解くべき問題 t){
if(t がもう分解できない){
t を処理;
return t の答え;
}else{
t1 = t を分解;
ans1 = solve(t1);
分解した残りと ans1 によりtの答を計算;
return t の答え;
}
}
階乗 n!=n*(n-1)*...*2*1 は n!=n*(n-1)! と左辺にも階乗を含む構造に分解 できます。 一方 0!=1 となります。 従って、プログラムは次のようになります。
int kaijo(int n){
if(n==0){
return 1;
}else{
return n*kaijo(n-1);
}
}
このプログラムを使って、 5! と 6! を求めなさい。
フィボナッチ数列とは、手前の数と、その手前の数の和を次々と求めてできる 数列です。
a0=1, a1=1 とすると、n 番目(n≧ 2)は an= an-1+ an-2 と書けます。 この時の n 番目の値を求めてみましょう。
組合せの数 nCm の求め方を考えます。 これは n 個の中から m 個を取り出す取り出し方は何通りあるかということで す。 ここで、n 個のものの中から一つのものに注目します。
従って、 nCm = n-1Cm + n-1Cm-1 が得られます。 なお、n 個のものから0 個を取る取り方や、 n 個全部を取り出す取り方はと もに 1 通りしかありません。つまり nC0 = nCn = 1 です。
この式を使って再帰的なプログラムを組み、 5C2、 20C2 を求めなさい。
ハノイの塔とは次のようなパズルです。 大きさが一回りずつ違う円盤を大きい順に下から並べます。 そして、次のルールでその円盤の山を移動させます。
以下に 3 枚での例を示します。
a | b | c | ||
---|---|---|---|---|
1 |
= == === --a-- |
--b-- |
--c-- |
|
2 |
== === --a-- |
= --b-- |
--c-- |
move 1 from a to b |
3 |
=== --a-- |
= --b-- |
== --c-- |
move 2 from a to c |
4 |
=== --a-- |
--b-- |
= == --c-- |
move 1 from b to c |
5 |
--a-- |
=== --b-- |
= == --c-- |
move 3 from a to b |
6 |
= --a-- |
=== --b-- |
== --c-- |
move 1 from c to a |
7 |
= --a-- |
== === --b-- |
--c-- |
move 2 from c to b |
8 |
--a-- |
= == === --b-- |
--c-- |
move 1 from a to b |
この解法を再帰的に考えます。 もし、hanoi(n-1,'a','b','c') が n-1 枚の円盤を a から b へ移動する解法 を出力するとします(c はもう一つの領域)。 すると、 n 枚の円盤を a から b へ移動する解法は次のように考えられます。
このようにすると hanoi(n,'a','b','c') の解法を出力します。
#include <stdio.h>
hanoi(int n, char x, char y, char z){
if(n==1){
printf("move 1 from %c to %c\n",x,y);
return;
}else{
hanoi(n-1,x,z,y);
printf("move %d from %c to %c\n",n,x,y);
hanoi(n-1,z,y,x);
return ;
}
}
main(){
hanoi(3,'a','b','c');
}
上のプログラムを動かして hanoi(3,'a','b','c') と hanoi(4,'a','b','c') の解法を求めなさい。