質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

4260閲覧

ハノイの塔非再帰版

choya

総合スコア1

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2020/11/27 12:50

C言語ハノイの塔について
初心者です。
以下のプログラムを非再帰に直した場合どうなるのか教えて頂きたいです。

#include<stdio.h>

void move(int no, int x,int y){
if(no>1) move(no-1,x,6-x-y);
printf("円盤[%d]を%d軸から%d軸へ移動¥n",no,x,y);
if(no>1) move(no-1,6-x-y,y);
}

int main(){
int n;
printf("ハノイの塔¥n円盤の枚数:");
scanf("%d",&n);
move(n,1,3);
return 0;
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

choya

2020/11/27 14:14

すみません。あまり規約を読んでいませんでした。以後気をつけます。
guest

回答3

0

Wikipedia「ハノイの塔」によりますと

  • いちばん小さい円盤とそれ以外の円盤を交互に動かす。
  • いちばん小さい円盤は常にB→C→A→B(nが偶数の場合)またはC→B→A→C(nが奇数の場合)の順に動かす。
  • いちばん小さな円盤以外の円盤を動かす場面では、動かせる方法は1通りしかない。

投稿2020/11/28 00:21

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Wikipedia の「ハノイの塔」の2進数による解析 をコード化してみました。

C

1#include <stdio.h> 2 3void move(int no) 4{ 5 for (int k = 1 << no, n = 1; n < k; n++) { 6 int a = (n-1 & n) % 3 + 1, b = ((n-1 | n) + 1) % 3 + 1; 7 if (!(no & 1)) a > 1 && (a = 5 - a), b > 1 && (b = 5 - b); 8 int i = 0; 9 while ((n>>i & 1) == 0) i++; 10 printf("[%d] %d -> %d\n", i+1, a, b); 11 } 12} 13 14int main() 15{ 16 int n; 17 printf("ハノイの塔\n円盤の枚数:"); 18 scanf("%d", &n); 19 move(n); 20 return 0; 21}

もっと簡単に書けるかもしれません。

投稿2020/11/28 02:51

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

angel_p_57

2020/11/28 05:11

分かり易さを採るならこれでしょうか。ctzは「2進数での末尾の0の数」で、gccなら __builtin_ctz() が使えます。 int ctz(int x) { return __builtin_ctz(x); } void move(int no, int x,int y){ int atab[2][3] = { { x,y,6-x-y }, { x,6-x-y,y } }; for ( int i=1; i<(1<<no); i++ ) { int t=ctz(i)+1; int j=i>>t; int k=(no-t)%2; printf("[%d] %d -> %d\n",t,atab[k][j%3],atab[k][(j+1)%3]); } }
guest

0

ベストアンサー

「プログラムを非再帰に直した場合」の目的がよく分からないのですが、一般に再帰で書かれたものを非再帰に直すのは単純ではないです。
※例外は「末尾再帰」、階乗 n!=n×(n-1)! のような再帰であればループに置き換えることができる。

コンパイラがこの手のプログラムから機械語を生成して、それで意図通り動くのは、スタックのようなデータ構造を絡めた処理に置き換えているからで、新しく関数を呼ぶ時は、一旦今の計算内容を脇に置いておいて ( スタックに積んで )、呼んだ関数が終わったら続きから再開する、そんな感じのことを自前でやれば見た目は非再帰になります。…それに意味があるのかどうか分かりませんが。

もし「『ハノイの塔』に限った非再帰版」というお話であれば、その出力結果を良く見て規則性をなぞれば、単なる 2^n-1 回のループになることが分かります。
例えば円盤 1 を動かすのはループの奇数回目に限る、とか。円盤 2 を動かすのはループの偶数回目 ( かつ4の倍数回目じゃない ) とか。円盤 3 を動かすのはループの4の倍数回目 ( かつ8の倍数回目じゃない ) とか。

投稿2020/11/28 01:29

angel_p_57

総合スコア1681

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問