• ベストアンサー

碁石、順列

こんばんわ。 つい最近 別件で質問させていただいたばかりですが、 またプログラミングに関して 解決できないことがありまして ここに来ました(汗) タイトルの通りの問題なのですが、 何個かある碁石の中から いくつか取り出して、それを並べる には 何通りの順列がありうるかを算出するプログラムを 作りたいのですが、 たとえば 白が2個、黒が2個あったとして そこからランダムに3個とった場合について説明 させていただきます。 今書いているプログラムは、 ランダムに取り出してきた3個を choice[]という配列に格納します。 そして、順列ですから 重複してはいけないということで 今まで生成した順列にかぶるものがないか 確認できなければ いけないので、重複のないように、今までに選んだ3個の並びを stock[][]という二次元配列に格納していくようにしました。 ここが問題になっています。ここでバグがおきていて(私の 無知により間違った記述をしているためと思われますが、) for(i=0;i<5;i++){ for(j=0;j<3;j++){ stock[i][j] = choice[j]; } } printf("stock:%s\n",stock[0]); *stock[i][j]は、あらかじめ'E'で初期化をしております。 上記のように書きました。 これは、選択した3つが入ったchoice[j]を、stockの中に 同じものがないかを確認して、なければ代入する という感じで 書いたものです。 で、printf文は、stock[0]つまり stock[0][0]~stock[0][2] を表示させて、choiceと同じ3つが入っているか確認したかった ためなのですが、 choiceがWBB(白、黒、黒の意味)のとき stock:WBBEEEEEEEEEEEE と表示されてしまいます。 私は、stock:WBB となることを期待していたのですが。。。 で、たとえば次に選択した3つがBWBだとしたら 前にストックしたWBBとは違うから またstock[][]に代入する ことにして、 stock[1]が、BWB となるようにしたいのです。 そうやって貯めていければ、たとえば 上記のように 2回目に選択したとき、 choiceが stock[][]の中にあるものと、一致したら 重複順列だからカウントしない というようなことができるのですが、 そもそもstockへの入り方が期待したものと違い よくわからないことになっているものですから、 すべて、”一致していない”のほうを通ってしまい、 正常に実行できないでおります。 いったい、何を勘違いしており、どのようにすれば 解決できるのでしょうか(>_<) どなたかアドバイスいただけますでしょうか。 お手数ですが、よろしくお願いいたしますm(_ _)m

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

  • ベストアンサー
  • yama5140
  • ベストアンサー率54% (136/250)
回答No.4

>choiceがWBB(白、黒、黒の意味)のとき >stock:WBBEEEEEEEEEEEE >と表示されてしまいます。 >私は、stock:WBB >となることを期待していたのですが。。。  みなさん言われるように文字列の終端には、\0 があること。  その \0 を入れるための配列の確保が必要です。 >stock[i][j]は、あらかじめ'E'で初期化をしております。  たっぷり(今回の例では、[ 5 ][ 3 ] → [ 5 ][ 8 ] 位)配列を用意し、  ★あらかじめ '\0' で初期化をするか、   nn = 0;   ・・   stock[ i ][ nn++ ] = choice[ j ];   stock[ i ][ nn ] = '\0';   ・・と  ★1文字代入の都度、次を '\0' で終端処理すれば間違いがないかと思います。   何度も繰り返すときは、こちらがもちろんお勧め。 なお、文字列の比較には、strcmp() を使えば平易かと思います。  http://www.bohyoh.com/CandCPP/C/Library/strcmp.html #include <stdio.h> #include <string.h> void main() {  char cStokA[ 5 ][ 3 ] = { "123", "456", "789" };  char cStokB[ 5 ][ 8 ] = { "123", "456", "789" }; // コンパイラが、\0 を  char cStokC[ 5 ][ 8 ] = { "123\0", "456\0", "789\0" }; // 冗長  char cStokD[ 5 ][ 8 ] = { { '\0' } }; // あらかじめ全てを '\0' で初期化  printf( "[%s]\n", cStokA[ 0 ] );  printf( "[%s]\n", cStokB[ 0 ] );  printf( "[%s]\n", cStokC[ 0 ] );  printf( "[%s]\n", cStokD[ 0 ] );  if( 0 == strcmp( cStokA[ 0 ], cStokB[ 0 ] ) ) printf( "cStokA[ 0 ] == cStokB[ 0 ]\n" );  if( 0 == strcmp( cStokA[ 0 ], cStokC[ 0 ] ) ) printf( "cStokA[ 0 ] == cStokC[ 0 ]\n" );  if( 0 == strcmp( cStokB[ 0 ], cStokC[ 0 ] ) ) printf( "cStokB[ 0 ] == cStokC[ 0 ]\n" ); } 注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • takoashi
  • ベストアンサー率39% (21/53)
回答No.3

char stock[3][3]; を char stock[3][4]; みたいにするんですよ。 stock[0][3] = 0: stock[1][3] = 0: stock[2][3] = 0: 文字列というのが、C言語ではどいうものなのか? 2重配列では、どのようにメモリが確保されるのか? ということを勉強しなおしたほうがいいです。

全文を見る
すると、全ての回答が全文表示されます。
  • salsberry
  • ベストアンサー率69% (495/711)
回答No.2

printf()の%sで出力するにはC言語の文字列の形になっている必要があります。"WBBEEEEEEEEEEEE"と表示されてしまうということは、文字列の終端を示す'\0'が"WBB"の直後に入っていないということです。おそらく最後の'E'の後にも'\0'を入れていないだろうと思うので、出力がそこで終わっているのは単なる偶然です。 配列の大きさを変えて'\0'を追加する、あるいは%sを使うのをやめるなどの方法を考える必要があるでしょう。

donntakosu
質問者

補足

ありがとうございます! いただいたアドバイスの '\0'を付加する というのを明示的に付け加えたところ ほんの少し解決に近づきました。 たとえば、今まで stock:WBBWEEとなっていたのが stock:WBBWとなってくれました。 しかし 本当はstock:WB と    stock:BW に分かれてほしいのですが stock[0]として表示させても やはり stock[0]とstock[1]がくっついて表示されます。。。 そういう現象が起きているので、 やはり stockの中とchoiceを比較して 同じ2文字があったら 重複するので追加しない という機能もうまくいっておらず 重複したのもかまわずにstockの中に追加してしまっているようなんです。。。 いったい 何が間違っているのでしょうか(>_<)

全文を見る
すると、全ての回答が全文表示されます。
  • takoashi
  • ベストアンサー率39% (21/53)
回答No.1

Eで初期化しているのだから、Eが出力されるのは正しいのでは?

donntakosu
質問者

補足

回答ありがとうございます。 プログラムはほぼ独学で もしかしたらとても基礎の 部分で勘違いしたまま覚えていることもあるかもしれず おばかな質問しているとしたらすみません 汗 Eで形だけ初期化しておりますが たとえば stockがstock[3][3]の大きさだとすると □□□ □□□ □□□ ですよね。。。 そこに Eで初期化したのだから E E E E E E E E E となるわけですよね。 そして、stock[0]にchoice(=WWB)を入れたとしたら W W B E E E E E E になりますよね。 この状態で printf("stock:%s \n",stock[0]); としたとき、 stock:WWBEEEEEE と表示されてしまうのですが、 stock[0] と記すと stock[0][0]~stock[0][2]の 行が0の部分だけをさすようにはならないのですか?? stock:WWBというふうに、行が0の部分だけ表示される と思っていたのですが。。。 なぜそこにこだわるかといいますと、 たとえば stock[0]: W W B stock[1]: W B W stock[2]: B B W となっていたとして、そこに新たにchoice(=WBW)という順列が 生成されても、choice とstock[0]~[2]を順に比較していき、 choice == stock[1]だから これは重複している、stockリスト には追加しない! と判定させたいのですが、 stock[0]といったとき、まるでこの行列すべてをさしているかのように 見えていたので、頭が混乱してしまっているところなのです。。。 この説明でも分かりづかたっらすみません(>_<)

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 配列における数値の比較について

    #include <stdio.h> int main(void) { int i[10],j,k,match; printf("10個の数字を入力してください:\n"); for(j=0;j<10;j++) scanf("%d",&i[j]); // 一致する数字があるかどうか調べる // for(j=0;j<10;j++){ match=i[j]; for(k=j+1;k<10;k++) if(match==i[k]) printf("%dが重複しています\n",match); } return 0; } このコードなのですが、一致する数字があるかどうか調べているところの、 for(k=j+1;k<10;k++) このコードの内容が理解できません。 特にkの初期値が k=j+1 になっているのはなぜなのでしょうか? 配列i[j]には1から9までの数値が格納されているので、それと一致する数値を見つけ出すには for(k=0;k<10;k++) と同じことをすればよいのではないでしょうか? アルゴリズムがどうしても分かりません。 どなたか教えてくださる方がいたらよろしくお願いします。

  • Excel VBA 重複値を排除するには?

    Excel VBAなのですが、配列に重複値を格納しないようにする方法あるでしょうか? For i = 0 To 100 '' ここに既出myStrを排除するしくみを入れる? s(i) = myStr Next myStrは"01"、"88"、"92"等々ランダムに変化します。 myStrの値が、すでにs(どこか)に格納済みだったら、 代入処理[ s(i)=myStr ] しないようにしたいのですが、 実現方法ないでしょうか? Perlなら$seen{$myStr}++を使って便利なのですが...

  • ポインタと {   } の関係とは

    戻り値が配列(ポインタ)で返す関数を二つ作りif文で選択できるようにしたら 各要素の値がうまく表示されません。 最初に配列の各要素に自分で値を代入するか、ランダムに値を代入させるか決めて、代入させた配列を最後に表示させたいわけです。 #include <stdio.h> int RegistData(int *); int RandomData(int *, int); void main(){ int mous[6]; int select; printf("自分で表示入力するときは1を、コンピュータに任せるときは0を入力してください。"); scanf(" %d", &select); if(select == 0){  *mous = RandomData(mous); }else if(select == 1){ *mous = RegistData(mous); } for( i = 0 ; i < 6 ; i++) printf("%d ", mous[i]); } printf("\n"); } RandomData(int *mous) { //rand()関数でランダムに各要素に値を代入する処理をします。 return *mous; } RegistData(int *mous) { //自分で要素に値を代入する処理をします。 return *mous; } ちなみに、あらかじめ要素に値を入れておくと正常にうごきます。 int mous[6] = { 10, 15, 12, 23, 33, 42};//動作確認用表示

  • 2次元配列を使ったC言語の九九表を作りたいんですが、方法がわかりません。

    C言語で、九九の表を作っているのですが2次配列を使わないでの方法なら出来るんですが、 2次配列を使うと出来なくなってします。 下記のように途中まで組んだのですが、どうしてもエラーがでてしまいます。 #include <stdio.h> int main(void) { int i,j,a[9][9]; printf(" "); for(i=1; i<=9; i++) printf("%3d", i); printf("\n"); for(i=0; i<9; i++){ for(j=0; j<9; j++) a[i][j]= {1,2,3,4,5,6,7,8,9},{2,4,6,8,10,12,14,16,18},{3,6,9,12,15,18,21,24,27},{4,8,12,16,20,24,28,32,36},{5,10,15,20,25,30,35,40,45,6,12,18,24,30,36,42,48,54,7,14,21,28,35,42,49,56,63},{8,16,24,32,40,48,56,64,72},{9,18,27,36,45,54,63,72,81} }; for(i=0; i<9; i++){ printf("%3d", i+1); for(j=0; j<9; j++) printf("%3d",a[9][9]); printf("\n"); } return 0; } とやったのですが…以下に書く部分が間違っているようで。 #include <stdio.h> int main(void) { int i,j,a[9][9]; printf(" "); for(i=1; i<=9; i++) printf("%3d", i); printf("\n"); for(i=0; i<9; i++){ for(j=0; j<9; j++) a[i][j]=□ } for(i=0; i<9; i++){ printf("%3d", i+1); for(j=0; j<9; j++) printf("%3d", □); printf("\n"); } return 0; } 色々調べたり、少しずつ変えながら試しているのですが、できません。 どなたかわかるかたいらっしゃいますか。間違いがわかりません… 配列を使用しなくても出来ることは、わかるのですが、配列を使うバージョンでもできるようになりたいんです。 私がしようとおもっているのは、81個分の値を先に計算し、9×9の2次元配列に格納し、次に81個の配列要素の値を出力したいのですが、 間違いと方法がわかる方いらっしゃいませんか。

  • 配列に順列を入れ、その順列を使いルール通りの組合せを作るには

    配列nを用意して、2*nの配列に1~Z、又は1~9までの数字を格納します。3の場合、123,132,213,231,312,321の順列で、ルールは1の時は1つ間を空けて1を、2の時は2つ間を空けて2を・・・ つまり、3の場合は 231213,312132 の二つがルールと合致しているので答えとなります。 1~Zまでで、上記のようにルールに当てはまる場合のみを出力するプログラムを書きたいのですがうまくいきません。下に考えてみたものを載せます。どなたか分かる方ご教授願います。 #include<stdio.h> int p[99]={0},a[99]={0}; int n; int count; main(){ int i; void perm(int k); while(1){ scanf("%d",&n); if(n<=0){break;} for(i=1;i<=n;i++){p[i]=i;} count=0; perm(1); } } void perm(int k){ int i,w; if(k>n){ count++; for(i=1;i<=n;i++){a[i]=p[i];} for(i=1;i<=n;i++){a[i+a[i]+1]=a[i];} printf("[%d]:",count); for(i=1;i<=2*n;i++){printf("%3d",a[i]);} printf("\n"); } else{ for(i=k;i<=n;i++){ w=p[k];p[k]=p[i];p[i]=w; perm(k+1); w=p[k];p[k]=p[i];p[i]=w; } } }

  • 多次元配列から重複を削除

    Perlにて$f[i][j]のような2次元配列でデータを格納しています。 ここの[i]列には重複したデータが入っているので、 それを排除して[i]列の重複なしの配列を新たに作りたいのですが うまくいきません。 for ($j=0; $j<= $index; $j++){ if($chlist[j]==$f[$i][0]){ $chlist[j]==$f[$i][0]; last; } } こんな感じで作ってみたのですが永遠にデータが入りません。

  • 完全順列の問題

    完全順列についての漸化式D ( n ) = ( n - 1 ) { D ( n - 2 ) + D ( n - 1 ) }がありますが、その証明方法がわかりません。(1)一番目がkでk番目が位置の場合(2)一番目がkで、k番目が1以外の場合 の二つに場合分けして解く方法は理解しました。 今回質問したいのは、「n枚の完全順列の個数をanとします。 (1)ここへn+1枚目の札をn+1番目に追加します。 n+1番目の札を1~n番目の札のどれか1枚と交換すれば、 n+1枚とも順番が一致しなくなります。よって、an個ある完全順列からn+1番目へはそれぞれn個ずつの完全順列が作れます。 (2)また、n個のうちk番目だけが揃ってしまっているものからも、 k番目の数とn+1番目の札を入れ替えれば、これも完全順列の1つとなります。n個のうちk番目だけが揃っている札の並べ方をbnとすると、 1~nまでのn個のbnから、それぞれ1通りずつの完全順列(の1部)が作れます。 以上のことより、次の漸化式が作れます。 an+1=nan+nbn   ……(i) k番目以外はn-1個の完全順列となっているため、 bn=an-1 (n≧2)が成り立ちます。これを(i)II代入して上の漸化式が求まります。」 という解説が理解できないということです。具体的な疑問点は、(1)、(2)のせれぞれの操作は各々理解しているものの、なぜこれを足し合わせればすべて網羅したことになるのかということです。他に数えもれがありそうのように思えます。そもそもなぜこのようなやり方なのでしょうか。 ご教授のほどよろしくお願いします。

  • 線形探索法のプログラムについて

    配列Aに格納されている数字を検索するプログラムより、 Aのプログラムでは配列Aに格納されている数字を検索(scanf("%d" , j)で入力)した にもかかわらず、「該当するデータがありませんでした」と表示されてしまいます。 Bのプログラムでは、配列Bに格納されている数字を検索(scanf("%d" , j)で入力)すると 「該当するデータがありました」と表示されます。 Aのプログラムで、------でかこってある部分に問題があると思われ、 いろいろと試してみましたが、未だにその理由をつかむことができません。 その理由を知りたく、書き込みを致しました。 ご教授の程宜しくお願い致します。 A. main(){ int i , j; int k = 0; int A[5] = {4 , 1 , 3 , 4 , 5}; printf("検索する数値を入力してください > "); scanf("%d" , j); --------------------------------------------------------------- for(i=0 ; i<5 ; i++){ if(A[i] == j){ printf("該当するデータはあります"); k++; } } --------------------------------------------------------------- if(k <= 0){ printf("該当するデータがありませんでした\n"); } return; } B #include<stdio.h> main(){ int i , j , k; int A[5] = {4 , 1 , 3 , 4 , 5}; printf("検索する数値を入力してください > "); scanf("%d" , j); for(i=0 ; i<5 ; i++){ if(A[i] == j){ k++; } } if(k>0){ printf("該当するデータはありました"); }else{ printf("該当するデータはありませんでした"); } return; }

  • ランダムに数字を並び変える方法は

    windows2000 Flash MX 1~9までの数字をランダムに発生させ配列に入れるには v_count=new Array(); for(i=1; i<10; i++) {   v_max=9   v_count[i]=Math.floor(Math.random()*v_max)+1  } と記述しました。 配列に格納されたランダムに発生した数字が9個ありますが当然同じ数字も含まれています。 これを数字が重複しないようにする方法が知りたいのです。 つまり1~9までの数字をランダムに並べ替えたいのですがどのような方法がありますか。教えて下さい。 説明が下手でスミマセン。 ご指摘いただければ補足します。

    • ベストアンサー
    • Flash
  • 乱数を配列へ格納(JavaScript)

    乱数を重複しないよう8個配列へ格納したいのですが、 格納の時点でエラーが発生します。 「オブジェクトでサポートされていないメソッドまたはプロパティです」 なぜでしょう? どなたかご教授下さい。 numbers = new Array(); // 空の配列宣言。 function make() { while(numbers.length < 8){ check = true; number = Math.floor(Math.random() * 100);// ランダムに0~99までの整数を取得。 for(i = 0; i < numbers.length; i++) { // 今取得したものと同じ乱数がないか、 if(number == numbers[i]) { // 配列の中身全てと比較。 check = false; } } if(check) { numbers.push(number); // 取得した乱数を配列に格納。 } } }

エアプリンタが見つかりません
このQ&Aのポイント
  • iPhoneから印刷しようとするとエアプリンタが見つかりませんと表示される。先日までは問題なくプリントできていた。
  • 関係があるとするとジェイコムのモデムの調子が悪く新しい機械に取り換えた。その後プリンタには新しいWiFiの設定をし、本体にも表示されている。
  • お使いの環境はiPhone12miniで、無線WiFiに接続されています。電話回線はジェイコムです。
回答を見る

専門家に質問してみよう