• ベストアンサー

組合せのアリゴリズム

例えば1,2,3を一列に並べるという順列の問題(1→2→3、1→3→2、2→1→3、2→3→1、3→1→2、3→2→1の3!=6通り) は再帰などを使って解けますが、 千の位(3,2)、百の位(1,4,7)、十の位(6)、一の位(2,6) のような各位の組合せの問題を解くにはどうすればよいでしょうか? 3→1→6→2、3→1→6→6、3→4→6→2、3→4→6→6、3→7→6→2、3→7→6→6、2→1→6→2、2→1→6→6、2→4→6→2、2→4→6→6、2→7→6→2、2→7→6→6 上記の例の総組合せの数は2×3×1×2=12(各位の掛算)になりますが、アドバイスをお願いします。 開発言語はGNU Cで、コンパイラはgccです。

質問者が選んだベストアンサー

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

(1)1,2,3を一列に並べる /* "123"の順列を表示する */ #include <stdio.h> #include <string.h> #include <malloc.h> static unsigned count; void choice(char *select,char *list){ int len,i,j; char *newSelect,*newList,*p; len=strlen(list); if(len==1){ printf("%s%c\n",select, *list); count++; return; } newSelect=(char*)malloc(strlen(select)+2); newList =(char*)malloc(len); for(i=0;i<len;i++){ for(j=0,p=newList;j<=len;j++){ /* 選んだ1文字を除く文字列を作る */ if(j!=i) *p++=list[j]; } sprintf(newSelect,"%s%c", select, list[i]); choice(newSelect, newList); } free(newSelect); free(newList); } void main(void){ count=0; choice("","123"); printf("%u通り\n",count); } (2)千の位(3,2)、百の位(1,4,7)、十の位(6)、一の位(2,6) /* [32][147][6][26]の順列を表示する */ #include <stdio.h> #include <string.h> #include <malloc.h> static unsigned count; char *table[]={ "32","147","6","26",NULL}; void choice(char *select, int level){ char *newSelect,*p; if(table[level]==NULL){ count++; printf("%s\n",select); return; } newSelect=(char*)malloc(strlen(select)+2); p=table[level]; while(*p){ sprintf(newSelect, "%s%c", select, *p++); choice(newSelect, level+1); } free(newSelect); } void main(void){ count=0; choice("",0); printf("%u通り\n",count); }

20centuryboy
質問者

補足

お返事ありがとうございます。 とても詳しくソースコードまで書いていただいて申し訳ないのですが、千の位の候補の3,2を"32"というリテラル文字列で扱うのではなく、int comb[][]={{3,1,6,2},{2,4,,6},{,7,,}}という2次元配列のようなもので扱いたいと思っています。そして各位にどれだけ値が入っているかを記憶しておくint check[]={2,3,1,2}という1次元配列を用意して、この二つの配列で総組み合わせを求められないかと考えていました。つまり各位の値をリテラル文字列のようにまとめるのではなく、各値をそれぞれ一つのデータとして扱って組み合わせたいと思っています。私の説明が不足していて申し訳ございませんでした。文章がうまくまとめられておらず分かりずらいと思いますが、もしよろしければアドバイスをお願いいたします。

その他の回答 (4)

回答No.5

No.1のコーディング例です。再帰を使っています。 (インデントを全角の空白にしています) #include <stdio.h> #define N 4 int comb[][N]={{3,2,0},{1,4,7},{6,0,0},{2,6,0}}; int check[N]={2,3,1,2}; int kotae[N]; void hyouji(void) {  int i;  for (i=0; i<N; i++) {   printf("%d ",kotae[i]);  }  printf("\n"); } void naraberu(int n) {  int i;  if (n==N) {   hyouji();  } else {   for (i=0; i<check[n]; i++) {    kotae[n] = comb[n][i];    naraberu(n+1);   }  } } int main(void) {  naraberu(0);  return 0; }

20centuryboy
質問者

お礼

諸事情により回答が遅くなってしまい大変申し訳ございませんでした。 アドバイスいただいたサンプルプログラムは大変わかりやすく、参考になりました。 combやcheck配列を再起関数のローカル変数として扱わないようにする点にはじめ気づかず、格闘していましたが無事動作することができました。 また機会があればアドバイスのほうよろしくお願いいたします。 最後にお礼が遅くなってすみませんでした。 どうもありがとうございました。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

#3の補足 combの内容(並び)が#2の補足で示されているものと異なりますが、 配列の下位のモノが並列に変化する (comb[][i]のようなこと) 方が私にとってなじみがよく好みですのでそう書いております。 もちろん comb[i][]のようにアクセスしてもかまいません。 同じことです。 老婆心にて。

20centuryboy
質問者

お礼

諸事情によりお返事が遅くなってしまい大変申し訳ございませんでした。 BLUEPIXYさんのサンプルプログラムを参考にcomb[i][]のようにアクセスして試してみたところ動作することが確認できました。 今回は何度もご丁寧な回答をしていただいてとても感謝しています。 また機会があればアドバイスのほうよろしくお願いいたします。最後にお返事が遅くなって本当にすみませんでした。どうもありがとうございました。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#2の補足について int comb[4][4]={ {3,2,0,0}, {1,4,7,0}, {6,0,0,0}, {2,6,0,0} }; int check [4]={ 2,3,1,2 }; は、#2(2)のプログラムを char table[4][4] = { {'3','2' ,'\0','\0'}, {'1','4' ,'7' ,'\0'}, {'6','\0','\0','\0'}, {'2','6' ,'\0','\0'} }; と見なすと int check [4]={ 2,3,1,2 }; は、あらかじめstrlenしたと見ると ほとんど同じだということがわかります。 組み合わせる数を int select[4]; の様に表現するか あるいは、 int select=0; として、 select = select * 10 + n; のように集計するかは、お好みでやればいいかと思います。

  • elmclose
  • ベストアンサー率31% (353/1104)
回答No.1

一例ですが、下記の手順を実行する関数を作成すれば良いのではないでしょうか。 step 1) さらに下位があればstep 2 ~ 3を実行し、なければ空列を値として返す。 step 2) 下位の順列を得る(再帰呼び出しでも可能)。 step 3) 現在位置の数(例えば、百の位ならば、1,4,7)それぞれに、上で得た下位の順列それぞれを連結させ、これで得られる全ての列を値として返す。 以上

20centuryboy
質問者

お礼

お返事ありがとうございます。 なかなかプログラムのスキルやアルゴリズムの知識がないため、アドバイスがあまり理解ができなかったのですが、頑張ってみたいと思います。

関連するQ&A

  • 数A「場合の数」の問題について

    次の問題の解き方が分かりません。 (1) 4ケタの整数のうち、各位の数が奇数のものは全部でいくつ? これは、奇数は1、3、5、7、9の5つなので、5×5×5×5で求めることが出来ますよね。 (2) (1)のなかで、各位の数が全部ことなるもの これは、(1)の求め方と同じく、全部違う数字がくるので、5×4×3×2でよいですよね? (3) (1)のうち、各位の数が順位大きくなるものはいくつか?(重複を許す) これは、重複の組み合わせや順列の公式を使ってもとめることができるのでしょうか? 樹形図を描く以外にどういう方法があるのか教えてほしいです! (4) (1)の数を小さいものから順番にならべるとき、5599は何番目の数か? これは、計算で求められますか? 千の位の数が、 5×5×5で125通り、 三千の位の数が同じく125通り、 ここまでで250通り、 5千百の位の数が・・・ というふうに樹形図のように考える以外に何か公式があれば教えてください!! 宜しくお願いします。

  • 順列と組み合わせの違い

    数学Aの「順列」と「組み合わせ」の違いが良く分かりません。 公式の使い方は分かるのですが、文章問題から順列、組み合わせどちらの公式を使えば良いのか分からないのです。教科書を何度読んでもイメージできないし、理解できません。 違いを教えてください。できれば例を用いて。

  • 順列・組み合わせの問題です。

    順列・組み合わせの問題です。 0,1,2,3,4の数字から異なる3個の数字を取ってできる3桁の整数は全部でいくつですか? という問題ですが、 一の位は5通り 十の位は4通り 百の位は2通りでという考えでよろしいでしょうか? よくわからないのですがお願いします。

  • Cをコマンドプロンプトから実行したい

     今晩は、Eclipse(CDT)でC言語を勉強している初心者です、宜しくお願いします。  WorkSpaceを作成して、そこに実際に作成したファイルを保存しています。  これをもし、コマンドプロンプトから動作させようとすると、どのファイルをどのように呼び出して、実行させて やればよいのでしょうか。  因みにEclipseのフォルダの中には、GNU>gcc>binというフォルダ構成?となっています。  また、GNU、gccのそれぞれの役割みたいなものはどういう意味でしょうか。  コンパイラらしきものというのはわかるのですが、色々と本を調べると、GNU、gccのどちらもコンパイラという風には 書いているのですが.........

  • gccコンパイラー

    今、gccでコンパイルするc言語のコンパイラーを探しています。 フリーでダウンロードできるいいコンパイラーはないでしょうか。 お勧めなどがありましたら教えてほしいです。 あと、C言語ではgccやbcc等のコンパイラーで プログラムソースの書き方容が変わったりするものなのでしょうか? 一応、ボーランド?のコンパイラーは持ってます。 ただ、今度OJTでUNIX環境のc言語開発の現場に行く事になり gccでコンパイルするもので勉強しとくようにいわれています。 宜しくお願いします。

  • 数Aの確率問題について

    確率の問題で、わからない解説があります 問.6人の生徒から委員長、副委員長、書記を1人ずつ選出する方法は全部で何通りか? 解説.異なるn個のものから、異なるr個を取り出して一列に並べる方法の数は…―― この解説の中で、 「一列に並べる」 とありますが、なぜ6人の生徒からそれぞれ1人ずつ選出して「一列に並べる」のですか(;^_^? 順列(順番を考える)と 組合せ(順番を考えない)とでは、求め方も答えも変わります。 例えば上の問題で順列なら、 nPrより 6P3=6×5×4 で120通り 組合せなら、 nCrより 6C3=(6×5×4)÷(3×2) で20通り のように… 問題を見て、順列か組合せかを見分けるのは無理なことなのでしょうか??

  • C言語での例外処理の検出方法とは?

    下記Linux環境にて、C言語で例外処理を検出したいのですが 何か方法は有りますでしょうか? 回答するにあたり、不足な情報がございましたらご指摘ください。 環境&コンパイラ  RedHat 7.3 2.96-110  Kernel 2.4.18-3 on an i686  gcc 2.96  GNU Make 3.79.1

  • ARMについて

    ARMを買ったときにWEBカメラモジュールつきの開発基盤を買ったんですけど、すでにコンパイラ済みで、そのままmakeすればWEBカメラを動かせるのはいいんですが、それでは意味がないと教師に言われ、そのカメラを別のマイコンに移植すると言う実験をしています そこで問題なのですが,すでにARM-Linux-gccでコンパイラ済みのプログラムを普通のgccに戻す手段はありませんか? またはARMを使ってgccにリンクするとか? コンパイラ済みのARM-Linux-gccを何らかの方法でgccに変えるとか? もし知っている人がいたら教えてください お願いします

  • 組み合わせの質問です

    こんにちは、組み合わせ論は趣味です。 さて、次のような問題の一般解は、どのように求めるのか、あるいは、どのような呼び方(例、数珠順列)をするのか、教えていただけませんか。 例題:『A色 2個、B色 3個、C色 5個のあわせて10個の玉がある。ここから、4個を取り出す場合、何通りあるか。1個も取り出されない色があっても良い。』 上記はあくまで例であり、『色の種類数がk種類、それぞれr1個、r2個、・・・、rk個の玉から、m個を取り出す場合』が知りたいことです。 完全回答でなくても、ヒントになるような考え方が分かるとうれしいです。 どうぞよろしくお願いいたします。

  • SPI対策について

    30代、初転職です。 一次選考を控えているのですが、 SPIがあるとのことで10年ぶりに勉強してますが、 非言語の順列・組み合わせについて 問題集を繰り返しやってますが、ピンときません。 根本理解ができてないからだと思いますが、 分かりやすい解説がある良サイトなどがあれば教えていただけますでしょうか? また、言語については問題集と同じ問題がでることはほぼなく、対策は難しいと思いますが、有効対策が何かありましたら教えていただけると助かります。

専門家に質問してみよう