• 締切済み

perl ハノイの塔の解に順番付けする方法

プログラミング初心者です。 サブルーチンを用いて、ハノイの塔の解を求める課題で詰まっています。 解自体は求めることができたのですが、それぞれの解の順番(輪を移動させる順番)を一緒に表示させよという指示が出ており、この方法がわかりません。 表示順に上から番号を振るという考え方でよろしいのでしょうか。 まず考え方自体が違うようであれば、そこから指摘して頂きたいと思います。 よろしくお願いします。 ちなみに現状ではこのようになっております。 #!/usr/bin/perl sub hanoi { my ($no , $x , $y , $z) = @_; if( $no = $no){ hanoi ($no-1,$x,$z,$y); print "Move", $no ,"from" , "$x" , "to" , "$z" , "\n"; hanoi ($no-1,$y,$x,$z); } } print"入力された枚数のハノイの塔の解(順番付き)\n"; $data=<>*1; hanoi($data , "A" , "B" , "C");

  • Perl
  • 回答数2
  • ありがとう数0

みんなの回答

  • namboku
  • ベストアンサー率50% (2/4)
回答No.2

「解の順番」というのは、以下のようなアウトプットを想定していると言うことでしょうか? 入力された枚数のハノイの塔の解(順番付き) (1) Move 1 from A to C (2) Move 2 from A to B (3) Move 1 from C to B (4) Move 3 from A to C (5) Move 1 from B to A (6) Move 2 from B to C (7) Move 1 from A to C だとすれば、以下のような以下のようなスクリプトになります。 -------------------------------------------------------------------------------------------- sub hanoi { my ($no , $x , $y , $z) = @_; if ($no == 1) { $cnt++; print "($cnt) Move ", $no ," from " , "$x" , " to " , "$z" , "\n"; } else { hanoi ($no - 1,$x,$z,$y); $cnt++; print "($cnt) Move ", $no ," from " , "$x" , " to " , "$z" , "\n"; hanoi ($no - 1,$y,$x,$z); } } print "入力された枚数のハノイの塔の解(順番付き)\n"; $cnt = 0; $data = 3; hanoi($data , "A" , "B" , "C"); --------------------------------------------------------------------------------------------

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.1

"Move" の後に表示される数字は、小さい順から付けられた輪の名称になります。3枚で実行すると、次のように表示されます。 Move1fromAtoC Move2fromAtoB Move1fromCtoB Move3fromAtoC Move1fromBtoA Move2fromBtoC Move1fromAtoC 初期状態の A のポールに 1, 2, 3 の輪が積まれているのを想起すれば、どの輪を移動したかわかるので適切な表示だと思います。指示の意味がもう1つわからないところがありますが.....。 1 2 3 A B C

関連するQ&A

  • ハノイの塔

    ★自分が理解している事 「(n-1)ハノイが解けると仮定するとnハノイも解けること」 は理解できます。 そして数学的帰納法によりすべての自然数についてハノイは「解ける」 ここまではわかります。 ★わからないのは、その「解き方」です。 「解ける」ことはわかるのですが「解き方」がわからないのです。 何故このプログラムで正解が表示されるのかが理解できないのです。 確かに、紙と鉛筆でプログラムの流れを追っていくと解けています。 しかし、何でこのプログラムで解けるのかがわからないのです。 棒xは出発点 棒yは目的地 棒zは作業棒 です。 (n-1)ハノイをひとかたまりと考え、作業棒Zに移す。 nハノイを目的地Yに移す。 (n-1)ハノイをひとかたまりと考え、目的地Yに移す。 そんな説明で確かに納得した気になりはします。 しかしこのプログラムでは(n-2)以下の場合についてはいっさい語っていません。 何かだまされてる気がします。 このプログラムでは(n-1)について語っていますが (n-2)以下については全く語っていません。 数学的帰納法により「解ける」ことは証明済みですが、 「その解き方」がこのプログラムでよいという「証明」はありますでしょうか? 理解のコツはありますでしょうか? よろしくお願いいたします。 #include<stdio.h> #include<stdlib.h> void hanoi(int n, char x, char y, char z) { if(n==0) {/* 何もしない */} else { hanoi(n-1,x,z,y); printf("%c->%c,",x,y); hanoi(n-1,z,y,x); } } int main(void) { int num; scanf("%d",&num); hanoi(num,'A','B','C'); return 0; }

  • ハノイの塔

    次のc言語で書かれたハノイの塔のプログラムをZ80で動作させたいのですが、アセンブルするとどうなるのでしょうか??教えてください。 void move(char n,char a,char b){ if(n>1)move(n-1,a,6-a-b); if(n>1)move(n-1,6-a-b,b); } int main(){ char n=5; move(n,1,2); }

  • ハノイの塔 関数内の進み方

    ■プログラムは後半に書いてます。よろしくお願いします。      no x y ――――――― 10行目 3 1 3 10行目 2 1 2 10行目 1 1 3 printf ■この後の5回(できれば10回)の進み方を教え貰えると嬉しいです。 ■わからない理由 printfのとき、(no, x, y) = (1, 1, 3)でno = 1。 そのため13行目は行われない。 しかし、returnもbreakもないためまた6行目に戻るのでしょうか?(答えを見ると6行目に行きそうです。) (no, x, y) はどのような値で関数が始まるのでしょうか? 9行目があるのにno=2or3で表示される理由がわからないです。 01|#include <stdio.h> 02|#include <conio.h> 03| 04|#define N 3 05| 06|void move(int no,int x,int y) 07|{ 08| static int i=1; 09| if(no>1) 10| move(no-1,x,6-x-y); 11| printf("%dを%d軸から%d軸へ移動 : %d\n",no,x,y,i++); 12| if(no>1) 13| move(no-1,6-x-y,y); 14|} 15| 16|int main(void) 17|{ 18| move(N,1,3); 19| 20| _getch(); 21| return(0); 22|}

  • C言語によるハノイの塔のプログラムの実行の流れ

    解きながら学ぶC言語の問題8-9のハノイの塔のプログラムについです。ソースコードは #include<stdio.h> #define N 3 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(void) { move(N,1,3); return 0; } ============================== 実行結果 1を1軸から3軸へ移動 2を1軸から2軸へ移動 1を3軸から2軸へ移動 3を1軸から3軸へ移動 1を2軸から1軸へ移動 2を2軸から3軸へ移動 1を1軸から3軸へ移動 ============================== 最近大学の講義でこのプログラムの実行の流れを習ったのですが、どうにもよく理解することができません。 まず、move(no,x,y)にはそれぞれno=3,x=1,y=3の数が入っていますよね。 そして、no>1なので、move(no-1,6-x-y,y)の式に代入してmove(3-1,1,6-1-3)となるとno=2,x=1,y=2となるのでmove(2-1,1,6-1-2)となるのでこのときno=1,x=1,y=3。 この時点でno>1ではなくなりprintf関数によって、1を1軸から3軸へ移動、2を1軸から2軸へ移動と表示されると言うことだと思っているのですが。 ここから先がさっぱりです、なぜ1を3軸から2軸へ移動となるのでしょうか? 一つもどってno=2,x=1,y=2のときmove(no-1,6-x-y,y)の式に代入されるということなのでしょうか? どうして急にmove(no-1,x,6-x-y)の式で計算していたものがmove(no-1,6-x-y,y)の式で計算するようになるのか、がわかりません。 どちらも条件分岐はif(no>1)ですし、このif文が何のためにあるのかもよくわからないのです。 自分でも書いていて要点がはっきりしませんが、どなたかお願いいたします。

  • CommonLispでハノイの塔の円盤の移動回数を数える。

    はじめまして。東吾と言います。 Lispを最近初めて、色々見ながらハノイの塔のプログラムを作ってみました。 それだけじゃ芸が無いから移動の回数を数えてみようとおもったんだけど、行き詰まってしまいました。 idouの出てきた回数を数えれば良いのは分かるんだけどうまく組みこめないんです。 よろしくお願いします。 とりあえず作ってみたハノイの塔のプログラムです。 (defun hanoi (n from to v) (if (= n 1) (idou 1 from to) (let ((n1 (1- n))) (hanoi n1 from v to) (idou n from to) (hanoi n1 v to from)))) (defun idou (n from to) (print `(move ,n from , from to, to)) )

  • perl 実数or複素数のみ出力する方法 and ゼロ割について

    この度はよろしくお願いします。 まずperlでこのプログラムを実行させると use Math::Complex; $y = 3 + 4*i; $z = 10 + i; print $y * $z, "\n"; print $y / $z, "\n"; 実数と複素数を含んだ解が出てきます。 質問は解の中の実数、もしくは複素数のみを出力したい場合どのような事をすれば良いのでしょうか? それと、『ゼロ割』と言うものなんですが これはある数をゼロで割ると無限大に飛んでいくと言う事でよろしいのでしょうか?

  • ハノイの塔のチェック関数

    ユニックス等のシステムコールを使ったハノイの塔を検査するプログラムです。質問したいのは円盤数、つまり塔の枚数が30枚で実行すると、チェックします。チェックされていいのですが20枚の時はされません。 なぜされるのかをおしえてください。 チェックされる条件は円盤番号が2回以上現れる。 0以外の番号の間には0がくるです。 チェック関数を抜き出すと void *Check(void *arg){ int i,nchecks=0; while(sw) { sleep(1); nchecks++; for(i=0;i<ndisks;i++) Z[i]=0; for(i=0;i<ndisks;i++){ if (A[i]!=0) { if (Z[A[i]-1]!=0) { fprintf(stderr,"Inconsistent(1)!!! (Tower-A Tries=%d)(i=%d)\n",nchecks,i); break;} Z[A[i]-1]=1; } if (B[i]!=0) { if (Z[B[i]-1]!=0) { fprintf(stderr,"Inconsistent(2)!!! (Tower-B Tries=%d)(i=%d)\n",nchecks,i); break;} Z[B[i]-1]=1; } if (C[i]!=0) { if (Z[C[i]-1]!=0) { fprintf(stderr,"Inconsistent(3)!!! (Tower-C Tries=%d)(i=%d)\n",nchecks,i); break;} Z[C[i]-1]=1; } } for(i=0;i<ndisks;i++) { if (Z[i]==0) { fprintf(stderr,"Inconsistent(4)!!! (Final Tries=%d)(i=%d)\n",nchecks,i); break;} } } }

  • 繰り返し計算で得られる解を、直接計算して求める方法

    こんにちは、 下記について、教えて下さい。 y=625.733*((2/5)*(1-x)*a2^2-(4/105)*(1+2*x)*a2^3); があります。 a2は a2->-((7*(-1+x))/(1+2*x))-s1; です。 s1は nが1のときは、s1=0 nが2以上のときは、s1=(92*n)/(y*10^6) となります。 nを増やして、yが0.1に一番、近づいたときの nを求めたいのですが、どのように計算すれば 良いでしょうか? 下記は、nを増やして、mathematcaを使用して数値計算で求めたものです。 答えは n=14675 y=0.0829778 となりました。 もっと、スマートに直接計算する方法を教えて下さい。 x=0.767476; a2=.; For[n=1,n<2*10^4,n++, If[nŠ1,s1=0]; If[n>1,s1=(92*n)/(y*10^6)]; y=625.733*((2/5)*(1-x)*a2^2-(4/105)*(1+2*x)*a2^3); a2=-((7*(-1+x))/(1+2*x))-s1; f=0.1; If[y-f<0,Print["n=",n]]; If[y-f<0,Print["y=",y]]; If[y-f<0,Break[]]; ]; 下記は、以前、ここでご教示頂いたものですが、 いろいろと計算しますと、計算値が、上記の繰り返し計算の値と 異なってしまいます。 x=0.767476; y=.; n=.; z=Solve[y-(625.733*((2/5)*(1-x)*(-((7*(-1+x))/(1+2*x))-(92*n)/(y*10^6))^2-(4/105)*(1+2*x)*(-((7*(-1+x))/(1+2*x))-(92*n)/(y*10^6))^3))Š0,n]; y=0.1; Simplify[z]

  • 繰り返し計算で求められる解を直接計算して求める方法

    こんにちは、 下記について、教えて下さい。 y=625.733*((2/5)*(1-x)*a2^2-(4/105)*(1+2*x)*a2^3); があります。 a2は a2->-((7*(-1+x))/(1+2*x))-s1; です。 s1は nが1のときは、s1=0 nが2以上のときは、s1=(92*n)/(y*10^6) となります。 nを増やして、yが5.9に一番、近づいたときの nを求めたいのですが、どのように計算すれば 良いでしょうか? 下記は、nを増やして、mathematcaを使用して数値計算で求めたものです。 答えは n=13822 y=5.89997 となりました。 もっと、スマートに直接計算する方法を教えて下さい。 x=0.767476; For[n=1,n<2*10^4,n++, If[n==1,s1=0]; If[n>1,s1=(92*n)/(y1*10^6)]; y=625.733*((2/5)*(1-x)*a2^2-(4/105)*(1+2*x)*a2^3); y1=y/.a2->-((7*(-1+x))/(1+2*x))-s1; If[y1-5.9<0,Print["n=",n]]; If[y1-5.9<0,Print["y1=",y]]; ];

  • 連立方程式が解を持つ条件を行列を使って求める方法

    x+2μy+λz=1 3x-μy+2λz=1 -2x+y+3λz=λ 上記の連立一次方程式が解を持つ条件を、行列を使って求める問題です。 μやλがなければ、 1 2 1 1 3 -1 2 1 -2 1 3 c として、解いていくのかと思いますが、 μやλがあることで、その後の変形をどうすればいいのか分かりません。 途中式も詳しく教えていただけると助かります。 何卒よろしくおねがいします。