N-Queen問題の解法とは?

このQ&Aのポイント
  • N-Queen問題を解くためのアルゴリズムを教えてください。
  • N-Queen問題は、どのように解けるのでしょうか?
  • N-Queen問題について、解法やプログラムのアドバイスをいただけませんか?
回答を見る
  • ベストアンサー

N-Queen 問題

 N-Queen問題を考えています。  なかなかうまくいきません。  どうやったら解けるか、アルゴリズムでも下の私が考えたプログラムでもいいんでアドバイスください。 (4×4の場合) #include<stdio.h> #define BYTESIZE 8 void printbits(unsigned i); struct data { int basho; unsigned l1,l2,tate,x; }; int main(void) { unsigned m,l,hojo=0; int kenchi,i,j,k; struct data a[5]; for(i=0;i<=3;++i) { l=1<<i; hojo|=hojo|l; } a[0].l1=0; a[0].l2=0; a[0].tate=0; for(kenchi=0;kenchi<=3;) { for(i=1;i<=4;) { a[i].x=0; for(j=a[i].x;j<=3 && ((~l)&hojo)==0;++j) { m=1<<j; a[i].l1=((a[i-1].l1)<<1)&hojo; a[i].l2=((a[i-1].l2)>>1)&hojo; a[i].tate=(a[i-1].tate)|m; l=(a[i].l1)|(a[i].l2)|(a[i].tate); a[i].x=j+1; } if((~l)&hojo) { a[i].basho=j; a[i].l1=(a[i].l1)|m; a[i].l2=(a[i].l2)|m; ++i; if(i==5) {for(k=1;k<=4;++k) printf("%d ",a [k].basho);printf("\n");} } if(j==3)--i; if(i==0) kenchi++; } } } void printbits(unsigned intval) { unsigned i; for(i=0;i<BYTESIZE*sizeof(unsigned);++i) printf("%d",(intval<<i&1<<BYTESIZE*sizeof(unsigned)-1)?1:0); putchar('\n'); }  tateで駒があった列、l1で左にずらしたもの、l2で右にずらしたものを表しています(うまく説明出来なくすいません)。 参考URL:http://oshiete1.goo.ne.jp/kotaeru.php3?qid=330589  

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

  • ベストアンサー
  • s2t
  • ベストアンサー率79% (47/59)
回答No.1

こんな感じで。 MinGWで確認しました。 #include <stdio.h> #include <stdlib.h> #define N 8 /* 8×8の場合 */ int v[N], x[2*N-1], y[2*N-1], z[N]; void printbits(void) { int i, j; static sol = 0; printf("\nAns. %d\n", ++sol); for(i = 0; i < N; i++) { for(j = 0; j < N; j++) { if(z[i] == j) printf("■"); else printf("□"); } printf("\n"); } } void recursivesums(int i) { int j; for(j = 0; j < N; j++) { if(v[j] && x[i+j] && y[i-j+N-1]) { z[i] = j; if(i < N-1) { v[j] = x[i+j] = y[i-j+N-1] = 0; recursivesums(i+1); v[j] = x[i+j] = y[i-j+N-1] = 1; } else printbits(); } } } int main(int argc, char *argv[]) { memset(v, 1, sizeof(v)); memset(x, 1, sizeof(x)); memset(y, 1, sizeof(y)); recursivesums(0); return 0; }

maroniichann
質問者

お礼

ありがとうございます!

関連するQ&A

  • もう一度質問します。

     N×N-Queen問題を考えています。  チェスの駒の置き方を考えるもので、ある駒を置いた同じ縦列・横列・斜め列には駒が置けない条件下にある時、N×Nの盤の上にN個の駒を置くパターンは何個あるかというものです。  tree構造とbit操作を用いて考えたいのですがなかなかうまくいきません。  どうやったら解けるか、アルゴリズムでも下の私が考えたプログラムでもいいんでアドバイスください。 (4×4の場合) #include<stdio.h> #define BYTESIZE 8 void printbits(unsigned i); struct data { int basho; unsigned l1,l2,tate,x; }; int main(void) { unsigned m,l,hojo=0; int kenchi,i,j,k; struct data a[5]; for(i=0;i<=3;++i) { l=1<<i; hojo|=hojo|l; } a[0].l1=0; a[0].l2=0; a[0].tate=0; for(kenchi=0;kenchi<=3;) { for(i=1;i<=4;) { a[i].x=0; for(j=a[i].x;j<=3 && ((~l)&hojo)==0;++j) { m=1<<j; a[i].l1=((a[i-1].l1)<<1)&hojo; a[i].l2=((a[i-1].l2)>>1)&hojo; a[i].tate=(a[i-1].tate)|m; l=(a[i].l1)|(a[i].l2)|(a[i].tate); a[i].x=j+1; } if((~l)&hojo) { a[i].basho=j; a[i].l1=(a[i].l1)|m; a[i].l2=(a[i].l2)|m; ++i; if(i==5) {for(k=1;k<=4;++k) printf("%d ",a [k].basho);printf("\n");} } if(j==3)--i; if(i==0) kenchi++; } } } void printbits(unsigned intval) { unsigned i; for(i=0;i<BYTESIZE*sizeof(unsigned);++i) printf("%d",(intval<<i&1<<BYTESIZE*sizeof(unsigned)-1)?1:0); putchar('\n'); }  tateで駒があった列、l1で左にずらしたもの、l2で右にずらしたものを表しています(うまく説明出来なくすいません)。 参考URL:http://oshiete1.goo.ne.jp/kotaeru.php3?qid=329998

  • 有限体GF(4)上の同次方程式で不定方程式

    連立方程式の解法ですが、手計算だとうまくいくのにプログラムにしようとするとうまくいきません。 さらに不定方程式なので解がないといわれてしまいます。誰かわかる方がいらしたらプログラムを 見て直していただきたいです。プログラムは以下の通り。 #define N 4 #define T 6 unsigned char gf[4]={0,1,2,3},fg[4]={0,1,2,3}; unsigned char gf[4]={0,1,2,3},fg[4]={0,1,2,3}; unsigned char ad[4][4]; /* 答えは 1,1,2 */ unsigned char s[3][3]={{1,3,1},{3,3,0},{1,0,3}}; /* 答えはzを不定として1と置き、x=z=1;y=0;になる筈だがならない */ //unsigned char s[][]={{2,2,2},{2,0,2},{2,2,2}} int add(int x,int y){ return ad[x][y]; } int mlt(int x, int y){ if(x==0||y==0) return 0; return ((x+y-2)%(N-1))+1; } int mltn(int n,int x){ int i,j; if(n==0) return 1; i=x; for(j=0;j<n-1;j++) i=mlt(i,x); return i; } int div(int x,int y){ if(x==0) return 0; return ((x-y+(N-1))%(N-1))+1; } void syn(){ int i,j,k,l,n; for(i=0;i<3;i++){ for(j=0;j<3;j++){ if(i==j){ if(s[i][j]==1){ for(l=0;l<3;l++){ for(k=0;k<3;k++){ s[l+1][k]=add(s[l+1][k],mlt(s[l+1][k],s[i][k])); printf("%d ",s[l][k]); } printf("\n"); } } // exit(1); if(s[i][j]!=1){ printf("%da \n",s[i][j]); n=div(1,s[i][j]); if(n==0){ printf("%d =\n",fg[s[i][j]]); exit(1); } for(k=0;k<3;k++){ if(s[0][0]==0){printf("%d?\n",s[0][0]); exit(1);} s[i][k]=mlt(n,s[i][k]); printf("%d ",s[i][k]); } printf("\n"); for(l=i;l<3;l++){ for(k=0;k<3;k++){ s[l+1][k]=add(s[l+1][k],mlt(s[l+1][k],s[i][k])); // printf("%d ",s[l][k]); } printf("\n"); } printf("\n"); for(l=0;l<3;l++){ for(k=0;k<3;k++) printf("%d ",s[l][k]); printf("\n"); } // exit(1); if(s[i][j]==0){ while(s[i][j]==0){ j++; } printf("i-j==%d\n",s[i+1][j]); if(s[i][j]!=0){ if(s[i][j]==1){ for(l=0;l<3;l++){ for(k=0;k<3;k++){ s[l+1][k]=add(s[l+1][k],mlt(s[l+1][k],s[i][k])); printf("%d ",s[l][k]); } printf("\n"); } } // exit(1); if(s[i][j]!=1){ printf("%da \n",s[i][j]); n=div(1,s[i][j]); if(n==0){ printf("%d =\n",fg[s[i][j]]); exit(1); } for(k=0;k<3;k++){ if(s[0][0]==0){printf("%d?\n",s[0][0]); exit(1);} s[i][k]=mlt(n,s[i][k]); printf("%d ",s[i][k]); } printf("\n"); for(l=i;l<3;l++){ for(k=0;k<3;k++){ s[l+1][k]=add(s[l+1][k],mlt(s[l+1][k],s[i][k])); // printf("%d ",s[l][k]); } printf("\n"); } printf("\n"); for(l=0;l<3;l++){ for(k=0;k<3;k++) printf("%d ",s[l][k]); printf("\n"); } }} // i++;j++; //exit(1); } } } } } for(i=0;i<3;i++){ for(j=0;j<3;j++) printf("%2d ",s[i][j]); printf("\n"); } } int main(){ int i,j; for(i=0;i<N;i++){ for(j=0;j<N;j++) ad[i][j]=fg[gf[i]^gf[j]]; } syn(); }

  • 迷路作成のプログラミング

    迷路作成のプログラミングをC++で作ったのですが、エラーが出ます。 どのように直せば良いか教えてください。 エラー内容は 'randoomize': 識別子が見つかりませんでした。 16 進型定数には、少なくとも 1 桁の 16 進数が必要です。 'kbhit': 識別子が見つかりませんでした 'getch': 識別子が見つかりませんでした です、、お願いします。 #include <stdio.h> #include <stdlib.h> #include <time.h> #define YOKO_MAX 200 #define ESC '\xlb' int n; int map[YOKO_MAX],count[YOKO_MAX]; int rr() { return rand() % 10>3; } void tate() { int i,j,k; printf("■"); for (i=0; i<n-1;i++) if(map[i]!=map[i+1] && rr()) { k=map[i+1]; count[k]=0; for(j=0; j<n; j++) if(map[j]==k) { map[j]=map[i]; count[map[i]]++; } printf(" "); } else printf("■"); printf("■\n"); } void last_tate() { int i,j,k; printf("■"); for (i=0; i<n-1;i++) { if(map[i]==map[i+1]) printf("■"); else { k=map[i+1]; for (j=0; j<n; j++) if (map[j]==k) map[j]=map[i]; printf(" ",map[i]); } } printf("■\n"); } void yoko() { int i,j; for (i=0; i<n; i++) if (count[i]>1 && rr()) { printf("■■"); for(i=0; i<n; i++) { if (count[j]==0) { count[j]=1; count[map[i]]--; map[i]=j;break; } } } else { printf("■"); } printf("■\n"); } void enter() { int i,k; k=rand() % n; for (i=0; i<n; i++) if(i==k) { printf("■"); } else { printf("■■"); } printf("■\n"); } void initialize() { int i; for (i=0; i<n; i++) { map[i]=i; count[i]=1; } randoomize(); } int main() { printf("無限に大きな迷路\n"); do { printf("\n迷路の横幅(2~200)?"); scanf("%d",&n); } while (n<2||n>=YOKO_MAX); printf("\n ESCキーを押すと止まる。\n"); initialize(); enter(); do { tate(); yoko(); } while (!kbhit()||getch()!=ESC); last_tate(); enter(); }

  • C++の数独をJavaに変換したいのですが

    C言語のプログラムをJavaに変換しようと思っているのですが、上手くいきません。 下記のプログラムを実行すると、一発で数独の解答が出来上がるようになっています。 Javaにはgotoがないので、そこをどのように変えたらいいのかで迷っています。 どう直したら良いのでしょうか。 #include<stdio.h> #include<stdlib.h> #include <time.h> int main(void) { int i,j,k,l,chk=0,num=0,tmp,count=0; int a[9][9]; srand((unsigned) time(NULL)); start: count=0; for(i = 0; i < 9; i++) for(j = 0; j < 9; j++) a[i][j]=0; for(tmp=1;tmp<10;tmp++){ num=0; while(num<9){ i = rand() % 9; j = rand() % 9; chk=0; for(k=0;k<9;k++) if(a[i][k]==tmp)chk=1; for(k=0;k<9;k++) if(a[k][j]==tmp)chk=1; for(k=(i/3)*3;k<(i/3)*3+3;k++){ for(l=(j/3)*3;l<(j/3)*3+3;l++){ if(a[k][l]==tmp)chk=1; } } if((chk==0)&&(a[i][j]==0)){ a[i][j]=tmp; num++; } if(count%100==99){ count++; for(i = 0; i < 9; i++) for(j = 0; j < 9; j++) if(a[i][j]==tmp)a[i][j]=0; num=0; } if(count>10000) goto start; count++; } } for(i = 0; i < 9; i++){ for(j = 0; j < 9; j++){ printf("%d ",a[i][j]); } printf("\n"); } return 0; }

    • ベストアンサー
    • Java
  • 2 ~ 200 の素数 a, b, c (a < b < c) が、b - a = c - b を満たすa,b,cをビット操作を用いて求め、すべてを表示せよ

    ちょっと考えてみました。でも、分かりません・・・まず、int型のintvalに200bitを割り当てて、intval=0としたいのですが、どうしたらいいのでしょう?? とりあえず考えてみたプログラムを誰か見て下さい!!お願いします。 #define BYTESIZE 200 #define MAX 200 main() { int i,j,intval=0; for(i=2;i<=MAX/2;i++) { if(intval&(1<<(i-1)){} else for(j=i*2;j<=MAX;j+=i)intval|=(1<<(j-1)); }/*素数を0、それ以外を1に for(i=2;i<=MAX/2;i++) for(j=2;j<=(MAX-i)/2;j++) if((intval&(1<<(i-1))&&(intval&(i+j-1))&&(intval&(1<<(i+2*j-1)))) print("%3d %3d %3d (%3d)\n",i,i+j,i+2*j,j); }/*三つ子の素数を調べ出力

  • 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"); } }

  • 数独のJavaプログラム

    数独の解答を一発で出すプログラムを考えています。 自分が考えたプログラムは下記の通りです。 import java.util.Random; public class NumberPlace { public static void main(String[] args) { int i, j, k, l, check=0, count=0, tmp; int a[][] = new int [9][9]; Random rnd = new Random(); int ran; for ( i=0; i<9; i++ ) for ( j=0; j<9; j++) a[i][j] = 0; count = 0; for ( i=0; i<9; i++ ) { for ( j=0; j<9; j++) { ran = rnd.nextInt(9); tmp = ran + 1; check = 0; for ( k=0; k<j; k++ ) if ( a[i][k] == tmp ) check = 1; for ( k=0; k<i; k++ ) if ( a[k][j] == tmp ) check = 1; for ( k=(i/3)*3; k<(i/3)*3+3; k++ ) for ( l=(j/3)*3; l<(j/3)*3+3; l++ ) if ( a[k][l] == tmp ) check = 1; if ( check == 0 ) a[i][j] = tmp; if ( check == 1 ) j--; if ( count > 50000 ) break; count++; } count = 0; } for ( i=0; i<9; i++) { for ( j=0; j<9; j++ ) { if ( a[i][j] < 10 ) { System.out.print(" "); } System.out.print(a[i][j]); } System.out.print("\n"); } } } これを実行すると、正しい数独の解が出来るまでに実行を20~30回。多い時は200回前後実行しないと出来ません。 実行結果(0は数独のルール上数字が入らない所) 9 3 6 5 4 1 7 8 2 1 7 4 2 9 6 5 3 0 5 2 8 7 3 0 0 0 0 2 1 5 3 7 8 4 6 9 8 6 3 4 1 9 2 7 5 4 9 7 6 5 2 1 0 0 7 5 1 8 6 4 9 2 3 3 8 2 9 0 0 0 0 0 6 4 9 1 2 5 8 0 0 これを一発で0がない状態にしたいのです。 因みにC言語だと下記のプログラムで一発で出るのですが。(前回質問したプログラム) int main(void) { int i,j,k,l,chk=0,num=0,tmp,count=0; int a[9][9];  srand((unsigned) time(NULL)); start: count=0; for(i = 0; i < 9; i++) for(j = 0; j < 9; j++) a[i][j]=0; for(tmp=1;tmp<10;tmp++){ num=0; while(num<9){ i = rand() % 9; j = rand() % 9; chk=0; for(k=0;k<9;k++) if(a[i][k]==tmp)chk=1; for(k=0;k<9;k++) if(a[k][j]==tmp)chk=1; for(k=(i/3)*3;k<(i/3)*3+3;k++){ for(l=(j/3)*3;l<(j/3)*3+3;l++){ if(a[k][l]==tmp)chk=1; } } if((chk==0)&&(a[i][j]==0)){ a[i][j]=tmp; num++; } if(count%100==99){ count++; for(i = 0; i < 9; i++) for(j = 0; j < 9; j++) if(a[i][j]==tmp)a[i][j]=0; num=0; } if(count>10000) goto start; count++; } } for(i = 0; i < 9; i++){ for(j = 0; j < 9; j++){ printf("%d ",a[i][j]); } printf("\n"); } return 0; } このプログラムを実行すると一発で解答が出ます。 上のJavaプログラムを下のプログラムのようにするにはどうしたら良いでしょうか。

    • ベストアンサー
    • Java
  • 5×5行列、固有値、固有ベクトル

    5つの値を入力し、それぞれの相対比を求めて行列にして、固有値と固有ベクトルを求めたいのですが、分からないので教えて下さい。下のプログラムは固有値を求めるものです。これは過去の質問にあったプログラムを少し変えてみたのですが、値が出てこないのでどうすればうまく出てくるのか教えて下さい。それと、固有ベクトルを求めるプログラムも教えて下さい。宜しくお願いします。 #include <math.h> #include <stdlib.h> #include <stdio.h> int main(void) { int i, j, k, l; double max,theta,x,y,a[5][5],b[5]; printf("値1: "); scanf("%d",&b[0]); printf("値2: "); scanf("%d",&b[1]); printf("値3: "); scanf("%d",&b[2]); printf("値4: "); scanf("%d",&b[3]); printf("値5: "); scanf("%d",&b[4]); printf("行列\n"); for(j=0;j<5;j++){ for(k=0;k<5;k++){ a[j][k]=b[k]/b[j]; printf("%1.3f ",a[j][k]); } printf("\n"); } while(1){ max=0; for(i=0;i<5;i++){ for(j=0;j<5;j++){ if (i!=j && max<fabs(a[i][j])){ max=fabs(a[i][j]); k=i; l=j; } } } if (max<1.0e-6) break; theta=(a[k][k]!=a[l][l])? atan2(-2*a[k][l],a[k][k]-a[l][l])/2:M_PI/4; for(i=0;i<5;i++){ x=a[i][k]; y = a[i][l]; a[i][k] = cos(theta) * x - sin(theta)*y; a[i][l] = sin(theta) * x + cos(theta)*y; } for (j=0;j<5;j++){ x=a[k][j]; y=a[l][j]; a[k][j]=cos(theta)*x-sin(theta)*y; a[l][j]=sin(theta)*x+cos(theta)*y; } } printf("固有値\n"); for (i=0;i<5;i++){ printf("%1.3f\n",a[i][i]); } return 0; }

  • FCC(面心立方)の位置に粒子を配置する方法

    main関数の中で以下のように書きました.よりよくするにはどうすればいいでしょうか.(計算速度,見た目) i=0; for(j=0;j<M;++j){ for(k=0;k<M;++k){ for(l=0;l<M;++l){ if(i<M*M*M){ rx[i]=0.01+0.5*L+a*(j-M/2); ry[i]=0.01+0.5*L+a*(k-M/2); rz[i]=0.01+0.5*L+a*(l-M/2); } ++i; } } } for(j=0;j<M;++j){ for(k=0;k<M;++k){ for(l=0;l<M;++l){ if(i<2*M*M*M){ rx[i]=0.01+0.5*L+a*(j-M/2)+a/2; ry[i]=0.01+0.5*L+a*(k-M/2)+a/2; rz[i]=0.01+0.5*L+a*(l-M/2); } ++i; } } } for(j=0;j<M;++j){ for(k=0;k<M;++k){ for(l=0;l<M;++l){ if(i<3*M*M*M){ rx[i]=0.01+0.5*L+a*(j-M/2)+a/2; ry[i]=0.01+0.5*L+a*(k-M/2); rz[i]=0.01+0.5*L+a*(l-M/2)+a/2; } ++i; } } } for(j=0;j<M;++j){ for(k=0;k<M;++k){ for(l=0;l<M;++l){ if(i<4*M*M*M){ rx[i]=0.01+0.5*L+a*(j-M/2); ry[i]=0.01+0.5*L+a*(k-M/2)+a/2; rz[i]=0.01+0.5*L+a*(l-M/2)+a/2; } ++i; } } }

  • C言語の配列の使い方について質問です。

    以下のプログラムを配列を使って見やすくしたいのですが、どのように作ったら良いでしょうか? 宜しくお願いします。 #include<stdio.h> int main(void) { int a, b, c, d, e, f, g, h, i, j, k, l, m ,n, o; /*5段目の処理*/ for(a = 1; a <= 15; a++) { for(b = 1; b <= 15; b++) { if(a == b) continue; for(c = 1; c <= 15; c++) { if(a == c || b == c) continue; for(d = 1; d <= 15; d++) { if(a == d || b == d || c == d) continue; for(e = 1; e <= 15; e++) { if(a == e || b == e || c == e || d == e) continue; // printf("%d %d %d %d %d\n", a, b, c, d, e); ////4段目//// if(a>b){ f=a-b; } else if(a<b){ f=b-a; } if(b>c){ g=b-c; } else if(b<c){ g=c-b; } if(c>d){ h=c-d; } else if(c<d){ h=d-c; } if(d>e){ i=d-e; } else if(e<d){ i=e-d; } // printf(" %d %d %d %d \n", f, g, h, i); /////3段目//// if(f>g){ j=f-g; } else if(f<g){ j=g-f; } if(g>h){ k=g-h; } else if(g<h){ k=h-g; } if(h>i){ l=h-i; } else if(h<i){ l=i-h; } // printf(" %d %d %d \n", j, k, l); /////2段目//// if(j>k){ m=j-k; } else if(j<k){ m=k-j; } if(k>l){ n=k-l; } else if(k<l){ n=l-k; } // printf(" %d %d \n", m, n); /////三段目///// if(m>n){ o=m-n; } else if(m<n){ o=n-m; } // printf(" %d \n", o); if(a != b != c != d != e != f != g != h != i != j != k != l != m != n != o){ printf("%d %d %d %d %d\n", a, b, c, d, e); printf(" %d %d %d %d \n", f, g, h, i); printf(" %d %d %d \n", j, k, l); printf(" %d %d \n", m, n); printf(" %d \n", o); } } } } } } }

専門家に質問してみよう