• ベストアンサー

4つの数字を用いて重複することなく並べる

題名のとおりなのですが 例えば{1,2,3,4},{2,3,4,1}などです。 これら24通りを[24][4]の要素をもつ2次元配列に入れたいのですがどうすればいいのでしょうか? 一応自分で作ってみたのですが作ってみていかにも冗長であると感じています。 アドバイス、回答よろしくお願いします。 #include <stdio.h> int main(void){ int i,j,n=5,m,p; int l[24][4]={{1,2,3,4},{2,1,3,4},{2,3,1,4},{3,2,1,4},{3,2,4,1},{4,2,3,1}}; for(i=0;i<6;i++){ for(j=0;j<3;j++){ n++; if(!j)for(p=0;p<4;p++)l[n][p]=l[i][p];     else for(p=0;p<4;p++)l[n][p]=l[n-1][p]; m=l[n][0]; l[n][0]=l[n][1]; l[n][1]=l[n][2]; l[n][2]=l[n][3]; l[n][3]=m; } } for(i=0;i<24;i++){ for(j=0;j<4;j++){ printf("%d",l[i][j]); } printf("\n"); } return 0; }

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

  • ベストアンサー
回答No.2

私が作ったソースコードは以下のようなものです 簡単な物にするつもりがややこしいコードになってしまいました…… 4つの数字だけでなく、任意の桁数でも機能します。 また「1357」の順列といったものも求められます。 //////////////////////////////////////////////////////////////////////////////// // #include <stdio.h> #include <stdlib.h> #include <math.h> void sample(int len, int *number_list, int *data_list); int main(int argc, char* args[]) { int i, j; int number_list[4], data_list[4 * 24]; // ここで1,2,3,4を設定 for (i = 0; i < 4; i++) number_list[i] = i + 1; // これだと1357を設定 // number_list[0] = 1; // number_list[1] = 3; // number_list[2] = 5; // number_list[3] = 7; // この関数が全ての順列を生成する sample(4, number_list, data_list); for (i = 0; i < 24; i++) { for (j = 0; j < 4; j++) { printf("%d ", data_list[i * 4 + j]); } printf("\n"); } getchar(); return 0; } void sample(int len, int *number_list, int *data_list) { // len : 桁数、最初は4 // number_list: 番号のリスト「1」「2」「3」「4」と入ってたら、これの順列をつくる // data_list : 作成した順列をここに格納して、関数を呼び出した側へ渡す int *ptmp; int i, j, k; int size; int size_prev; if (len == 1) { data_list[0] = number_list[0]; return; } size = 1; for (i = 1; i <= len; i++) { size *= i; } size_prev = size / len; ptmp = (int *)malloc(sizeof(int) * (len - 1) * size_prev); sample(len - 1, &number_list[1], ptmp); for (i = 0; i < len; i++) { for (j = 0; j < size_prev; j++) { data_list[i * len * size_prev + j * len + i] = number_list[0]; for (k = 0; k < len - 1; k++) { data_list[i * len * size_prev + j * len + ((i + k + 1) % len)] = ptmp[j * (len - 1) + (k % (len - 1))]; } } } free(ptmp); }

ebinamori
質問者

お礼

回答有難うございます。 data_list[i * len * size_prev + j * len + ((i + k + 1) % len)] の部分は data_list[~][~]の形で書くとどのようになるのでしょうか?

その他の回答 (3)

noname#5537
noname#5537
回答No.4

C++ でよければ,標準ライブラリのおかげで以下のようにすっきり書けます。 C でも std::next_permutation と同じような動作をする関数を用意してやればすっきり書けると思います。 #include <iostream> #include <algorithm> int main(int argc, char* argv[]) {  int x[24][4]; // ここに結果を格納  int tmp[4] = { 1, 2, 3, 4 };  // 順列の生成  for (int i=0 ; i<24 ; i++) {   std::copy(tmp, tmp + 4, x[i]);   std::next_permutation(tmp, tmp + 4);  }  // 表示  std::ostream_iterator<int> it(std::cout);  for (int i=0 ; i<24 ; i++) {   std::copy(x[i], x[i] + 4, it);   std::cout << std::endl;  }  return 0; }

ebinamori
質問者

お礼

C言語しか勉強していないので 部分的にしか分りませんが 当たり前なのかもしれませんがちゃんと動きました。 アドバイスありがとうございました。

回答No.3

> data_list[i * len * size_prev + j * len + ((i + k + 1) % len)] > の部分は > data_list[~][~]の形で書くとどのようになるのでしょうか? このコードで使用しているdata_listは1次元配列のポインタとして使用しているため、2次元配列のdata_list[~][~]の形に書き表すことはできません。 ただ、意味としてはebinamoriさんが使用していた配列lと、 data_list[i * len * size_prev + j * len + k]  : l[i * size_prev + j][k] という形で対応します。 data_listの中身は以下のような形になっています。 1次元の配列を2次元として扱っています。 {1,2,3,4, 1,2,4,3 ……} 0番目から3番目までは一つ目の順列 4番目から7番目までは二つ目の順列 ・ ・ ・

ebinamori
質問者

お礼

再び回答有難うございます。 勉強になりました。

回答No.1

スピードは期待できませんが、シンプルにこういうのはどうでしょうか。 #include <stdio.h> int iSrc[4] = { 1, 2, 3, 4 }; void main() {   int i, j, k, l;   int iIndex;   int iDst[24][4];   iIndex = 0;   for( i=0; i<4; i++ ) {     for( j=0; j<4; j++ ) {       if( i != j ) {         for( k=0; k<4; k++ ) {           if( k != i && k != j ) {             for( l=0; l<4; l++ ) {               if( l != i && l != j && l != k ) {                 iDst[iIndex][0] = iSrc[i];                 iDst[iIndex][1] = iSrc[j];                 iDst[iIndex][2] = iSrc[k];                 iDst[iIndex][3] = iSrc[l];                 iIndex++;               }             }           }         }       }     }   }   for( iIndex=0; iIndex<24; iIndex++ ) {     printf( "%d, %d, %d, %d\n", iDst[iIndex][0], iDst[iIndex][1], iDst[iIndex][2], iDst[iIndex][3] );   } }

ebinamori
質問者

お礼

私のと違い iSrcの初期値を入力できるようにすれば どのような数字でも24通りを返してくれる 関数を作れますね。 回答有難うございました。

関連するQ&A

  • CからVB

    以下のプログラムはC言語で作成されています。 これをVBで作成したいです。 教えてください。 #include <stdio.h> #include <stdlib.h> double *alloc(int r,int n,int m); void input(double *p,int r,int n,int m); void sumup(double *p,int r,int n,int m); int main(void){ int r, n, m; double *p; // 行列サイズ入力 printf("input r n m "); scanf("%d %d %d",&r,&n,&m); // 行列領域取得 p = alloc(r,n,m); // 行列要素入力 input(p,r,n,m); // 行列の和 sumup(p,r,n,m); //終了,行列領域解放 free(p); return 0; } double *alloc(int r,int n,int m){ double *p; printf("MATRIX[r=%d][n=%d][m=%d]\n\n",r,n,m); p = (double*)malloc(sizeof(double)*r*n*m); if( p == NULL){ printf("error! malloc failed.\n"); exit(-1); } return p; } void input(double *p,int r, int n,int m) { int i,j,k; for(i = 0; i < r; i++){ for(j = 0;j < n; j++){ for(k = 0; k < m; k++){ printf("input MATRIX[%d][%d][%d]= ",i,j,k); scanf("%lf",&p[i*(n*m)+j*m+k]); } } } printf("\n"); } // 行列の和 void sumup(double *p,int r,int n,int m){ int i, j, k; // 0.0, not 0!!! double sum = 0.0; printf("sum of %d matrices:\n",r); for(j = 0; j< n; j++){ for(k = 0;k < m; k++){ sum=0; for(i = 0;i < r;i++){ sum += p[i*(n*m)+j*m+k]; } printf("\n%2f",sum); } } printf("\n"); }

  • C言語 プログラミング 行列演算

    下記のプログラムのおかしい点と解決法を教えてください。 コンパイルは通りますがうまく動きません。。 #include<stdio.h> #define MAX 500 int main(void){ int matrA[MAX][MAX],matrB[MAX][MAX],matrC[MAX][MAX],l,m,n,i,j,k; printf("lとmを入力してください:"); scanf("%d",&l); scanf("%d",&m); printf("行列Aを入力してください"); for(i=0;i<l;i++){ printf(">"); for(j=0;l<m;j++){ scanf("%d",&matrA[i][j]); } printf("\n"); } printf("nを入力してください(m = %d):",m); scanf("%d",&n); printf("行列Bを入力してください"); for(i=0;i<m;i++){ printf(">"); for(j=0;j<n;j++){ scanf("%d",&matrB[i][j]); } printf("\n"); } printf("C=\n"); for(i=0;i<l;i++){ for(j=0;j<n;j++){ for(k=0;k<m;k++){ matrC[i][j]+=matrA[i][k]*matrB[k][j]; } printf("%d",matrC[i][j]); } printf("\n"); } }

  • C言語の実行について、

    #include <stdio.h> #define N 2 void main(void) { int i ,j ; for( i=1 ; i <= N ; ++i) { for( j=i ; j < N+2 ; ++j) { printf("j=%d\n",j); } printf("i=%d\n",i); } } を実行すると、 j=1,j=2,j=3,i=1,j=2,j=3,i=2となったんですが、 どういった順序で行われているのでしょうか? よろしくお願いします。

  • c言語 行列のn階乗のプログラム

      1 2 -1 D= 3 0 -2   -1 1 2 の3次正方行列のn乗を計算するプログラムを作成しています。 いろいろと試してみましたがうまくいきません。 どなたか教えていただけるとうれしいです。 よろしくおねがいします。 #include <stdio.h> int main(void) { int a[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int b[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int s[3][3]; int m,n; int i,j,k; printf("[A]^n;n = ");scanf("%d",&n); for (m=2;m <= n;m++){ for (i=0;i<3;i++){ for (j=0;j<3;j++){ s[i][j] = 0; for(k=0;k<3;k++){ s[i][j] =s[i][j] + a[i][k] * b[k][j]; } } } for(i=0;i<3;i++){ for(j=0;j<3;j++){ b[i][j]=s[i][j]; } } printf("%3d",s[i][j]); putchar('\n'); } return (0); }

  • 組み合わせ

    n個の集合からp個を取る組み合わせの総数を出力するプログラムなんですが nCp=n!/p!(n-p)!という式を使い #include<stdio.h> int kaijo(int m); int comb(int n,int p); int main(void) { int i,j; printf("n="); scanf("%d",&i); printf("p="); scanf("%d",&j); printf("comb(%d,%d)=%d\n",i,j,comb(i,j)); } int kaijo(int m) { if(m>0) return(m*kaijo(m-1)); else return 1; } int comb(int n,int p) { if(n>0) return((n*kaijo(n-1))/(p*kaijo(p-1)*(n-p)*kaijo(n-p-1))); else return 1; } と書いてみたのですがこれではnが大きいとC言語のint型で扱える最大値を超えてしまい正しい結果が出力されません。  そこでint型を使ったままでnやpが大きい場合でもある程度出力できるようにしたいのですがどう改良したらよいのでしょうか? おそらくnCp=n*(n-1)*・・・*(n-p+1)/p!という式を使うのですがよく分かりません。よろしくお願いします。

  • 行列の計算

    #include<stdio.h> #define N 2 #define M 3 void hyoji(float[][M]); int main(){ int i,j,k; float a[N][M] = {{2.0,2.0,2.0},{2.0,2.0,2.0}}; float b[M][M] = {{1.0,1.0,1.0},{2.0,2.0,2.0},{1.0,1.0,1.0}}; float c[N][N]; for(i=0; i<N; i++){ for(j=0; j<M; j++){ c[i][j] = 0; for(k=0; k<M; k++){ c[i][j] += a[i][k] * b[k][j]; } } } hyoji(c); return(0); } void hyoji(float x[][M]){ int i,j; for(i=0; i<N; i++){ for(j=0; j<M; j++){ printf("%4.1f ",x[i][j]); } printf("\n"); } } 以上のプログラムで 行列aと行列bをかけ合せた行列cを求めるのですが コンパイルすると 8 8 8 8 8 1 となり、正しい結果がでません。 なにが間違っているのでしょうか?? よろしくお願いします。

  • C言語 エラー表示 break の位置が誤っている(関数 main ) 

    #include<stdio.h> int main(void){ int n,i,j,k; char c='*'; printf("正の整数:"); scanf("%d",&n); if(n>0){ for(i=1;i<=n;i++){ printf("%d",i); for(j=1;j<=n+1-i;j++){ if(j==1){ if(i-1>0){ for(k=i-1;k>0;k--){ printf(" "); } } } printf("%c",c); } printf("\n"); } } break; return 0; } これをコンパイルすると「break の位置が誤っている(関数 main )」と表示されるのですが何でですか? 困ってます↓

  • C *での三角形描画

    課題で*を使って三角形を描画するプログラムを作るんですが、ネットで見たかぎり、 #include<stdio.h> int main() { int n, i, j, k, l; printf("段数を入力してください:"); scanf("%d", &n); for(i = 0; i < n; i ++) { for(j = 0; j < n; j ++) { for(k = 0; k < n*n-i*n-j-1; k ++) printf(" "); for(k = 0; k < i; k ++) { for(l = 0; l < j*2+1; l ++) printf("*"); for(; l < n*2; l ++) printf(" "); } for(k = 0; k < j*2+1; k ++) printf("*"); printf("\n"); } } return 0; } となっているのが、  段数を入力してください:2     *    ***   *   *  *** *** という風に表示されるので、これを  段数を入力してください:2     *    *** という形に表示させられるよう変更すべき箇所を教えてください。

  • pow

    「1~10までの数、 その2乗、 その3乗」を10行出力するものです。 なぜか5^2 = 24 なってしまいました。なぜですか。お願いします。 #include <stdio.h> #include <math.h> int main(void) { int i, j; for (i = 0; i < 10; i++) { for (j = 0; j < 3; j++) { printf("%4d ", (int)pow(i+1, j+1)); } printf("\n"); } return 0; }

  • ピラミッド表示プログラム。

    ピラミッドを表示させるプログラムを考えています。 例えば3段の場合   *  *** ***** っというような表示です。 #include <stdio.h> void spira(int n); main() { int a; printf("段数は:"); scanf("%d",&a); spira(a); } void spira(int n) { int i,j=1,a,b,k; for(a=n;a>0;a--){ for(b=a-1;b<=n;b--){ printf(" "); } k=(j-1)*2+1; for(i=1;i<=k;i++){ printf("*"); } j++; printf("\n"); } } このように考えてみたのですが、無限ループになって表示できません。 どこが悪いでしょうか? 無限ループの原因はどうやったら解消されるでしょうか?

専門家に質問してみよう