第9講 関数の再帰的使用
第7話 関数の再帰的使用によるn次順列生成解説その4
コード再掲
#include<iostream>
using namespace std;
void f(int g);
void h();
int x[15],n;
long cn;
void main(){
cout<<"何次順列を生成しますか?"<<endl;
scanf("%d",&n);
cout<<endl;
cn=0;
f(0];
cout<<n<<"次順列が"<<cn<<"個生成されました。"<<endl;
}
void f(int g){
int i,j;
for(i=1;i<n+1;i++){
x[g]=i;
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
tobi:;
}
}
void h(){
for(char i=0;i<n;i++)cout<<x[i]<<" ";
cout<<endl;
}
解説
これでf (2)の3回目の生は終わりを告げ、消滅しf (1)へと戻ります。
そして、for文のi++により
となりますが、これは
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
によってチェックされてしまい、
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
無視されますから、for文のi++により
今回は
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
の試験に合格して
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
命令が実施され、f (2)の4回目の発生となります。
for(i=1;i<n+1;i++){
x[g]=i;
によって
3つともセルの内容が違いますので、
試験
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
はあっさりクリアして
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
の否定側の
else{
h();
cn++;
}
の命令が遂行され、4個目の順列
をコンソールにはき出します。
for文のi++により、
となりますが、これは1番目のセルと3番目のセルが同じなので、
検査
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
に抵触して、
となります。
今度は、2番目のセルと3番目のセルの内容が同じなので、やはり
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
の試験をクリアできません。
これで、f (2)の4回目の生が寿命を迎え、消滅します。
そして、セル番号1の世界も天寿を全うし、
2度目の消滅を体験します。
for文のi++により
となり、g=0なので試験
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
スルーされ、
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
の肯定側
if(g+1<n){
f(g+1);
}
が実行されf (1)の3度目の誕生を迎えます。
for(i=1;i<n+1;i++){
x[g]=i;
によって、
これは、2つのセルに内容が違いますので、
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
の肯定部分が遂行され、f (2)の5度目の生誕となります。
for(i=1;i<n+1;i++){
x[g]=i;
によって、
と変化していって、はじめて3つのセルの内容がすべて異なり、
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
の否定部分の命令が遂行され5個目の順列
がコンソールに出力されます。
以下、
セル番号2の世界の5度目の消滅。
と変化していき、6個目の順列
がコンソールに打ち出されます。
セル番号2の世界の6度目の消滅。
セル番号1の世界の3度目の消滅。
セル番号0の世界のはじめての消滅を迎え、
プログラムはf (0)を呼び出してから
はじめてPrivate Sub CommandButton1_Clickに戻り、
自分の任務をすべて完遂し終焉を迎えます。
プログラムは、消滅しましたが、コンソールには結果
が燦然と輝いています。
最後の方、叙述を簡単にしましたが、
簡略にした部分を皆さんが補ってください。
詳しい記述を延々と繰り返したのでは、
逆に読む気力が失せると考え、簡単にしました。
n=3を選んだ理由はお分かりですね。
n=2ではトレースとして簡単すぎます。
しかし、n=4では、私も書く気になれませんし、
読む皆さんもウンザリですよね。
みなさん、n=4のトレースは大変ですが、
頭の中でやってみてください。
コンピュータの動きを追うことはとても大切なことです。
では、n次順列生成
#include<iostream>
using namespace std;
void f(int g);
void h();
int x[15],n;
long cn;
void main(){
cout<<"何次順列を生成しますか?"<<endl;
scanf("%d",&n);
cout<<endl;
cn=0;
f(0];
cout<<n<<"次順列が"<<cn<<"個生成されました。"<<endl;
}
void f(int g){
int i,j;
for(i=1;i<n+1;i++){
x[g]=i;
if(g>0){
for(j=0;j<g;j++){
if(x[g]==x[j])goto tobi;
}
}
if(g+1<n){
f(g+1);
}
else{
h();
cn++;
}
tobi:;
}
}
void h(){
for(char i=0;i<n;i++)cout<<x[i]<<" ";
cout<<endl;
}
プログラムを改良して、
n次魔方陣自動生成プログラムを作成してください。
コードを複雑にしすぎないために
int x[30][30],n;
long cn;
はグローバル配列およびグローバル変数にしておきましょう。
第8講で作った方式では、
4次が限界ですが、
将来は改良して30次魔方陣までも作成可能にしますので、
配列は大きめにx[30][30]にしてあります。
n次魔方陣の行などの合計は
n*(n*n+1)/2
で計算できます。
なぜなら
(1+2+3+・・・+n*n)÷n
=n*n(n*n+1)/2÷n
=n*(n*n+1)/2
です。
さあ、汎用的魔方陣自動生成ソフトに挑戦しましょう!
第6話へ 第8話へ
魔方陣 数独で学ぶ VBA 入門
数独のシンプルな解き方・簡単な解法の研究
VB講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)
初心者のための VC++による C言語 C++ 入門 基礎から応用まで第1部
eclipse java 入門
java 入門 サイト 基礎から応用まで
VC++ C言語 C++ 入門 初心者 基礎から応用まで
本サイトトップへ