• 締切済み

数独を解くアルゴリズム

バックトラック法で解いているのですが、どこがおかしいのか見当もつかないので教えてください。 コンパイルエラーはありません。 表示の関数は省いてあります。 よろしくお願いします。 #include <stdio.h> #define M 3 //小さいブロックのサイズ #define N M*M //全体のサイズ #define MTX N*N //全体のマス数 int sudoku[N][N]={    {0,2,4,5,0,0,6,0,0},    {0,0,6,3,2,0,0,0,4},    {0,0,5,0,9,0,0,8,3},    {0,0,8,4,0,3,0,0,1},    {0,6,1,9,0,0,4,3,0},    {7,0,0,1,0,0,5,0,0},    {8,3,0,0,4,0,9,0,0},    {4,0,0,0,3,5,8,0,0},    {0,0,7,0,0,9,3,4,0}    }; /* 候補がOKかどうかチェック */ int OKkouho(int x, int y, int k) {    int i,j;    int p,q;    for(i=0; i < N; i++){ //その行に候補は入るか       if(sudoku[y][i] == k)          return 0;    }    for(j=0; j < N; j++){ //その列に候補は入るか       if(sudoku[j][x] == k)          return 0;    }    p = x/M*M;    q = y/M*M;    //そのブロックに候補は入るか    for(j = q; j < q+M; j++){       for(i = p; i < p+M; i++){          if(sudoku[j][i] == k)             return 0;       }    }    return 1; } void Solve(int level) {    int k;    int x,y;    if(level >= MTX){       printf("OK");       return;    }    x = level%N;    y = level/N;    if(sudoku[y][x])       Solve(level+1);    else{       for(k = 1; k <= N; k++){          if(OKkouho(x,y,k)){             sudoku[y][x] = k;             Solve(level+1);             sudoku[y][x] = 0;             }       }    } } int main(void) {    Solve(0);    return 0; }

みんなの回答

回答No.1

#include <stdio.h> #define M 3 //小さいブロックのサイズ #define N (M*M) //全体のサイズ #define MTX (N*N) //全体のマス数 //あっているかわからないが,とりあえずsudokuに設定されている //データでは /* 3,2,4,5,8,1,6,9,7, 9,8,6,3,2,7,1,5,4, 1,7,5,6,9,4,2,8,3, 2,9,8,4,5,3,7,6,1, 5,6,1,9,7,2,4,3,8, 7,4,3,1,6,8,5,2,9, 8,3,2,7,4,6,9,1,5, 4,1,9,2,3,5,8,7,6, 6,5,7,8,1,9,3,4,2, */ //という結果が求まった。 //念のために括弧で括ってみた。 //個人的な見易さの関係で一行ではなく複数行でif文を記述している //また,普通はしないだろうが,やっぱり気になるのでif(Solve(level+1))とせず //1と比較している。 int sudoku[N][N]={ {0,2,4,5,0,0,6,0,0}, {0,0,6,3,2,0,0,0,4}, {0,0,5,0,9,0,0,8,3}, {0,0,8,4,0,3,0,0,1}, {0,6,1,9,0,0,4,3,0}, {7,0,0,1,0,0,5,0,0}, {8,3,0,0,4,0,9,0,0}, {4,0,0,0,3,5,8,0,0}, {0,0,7,0,0,9,3,4,0} }; /* 候補がOKかどうかチェック */ int OKkouho(int x, int y, int k) { int i,j; int p,q; for(i=0; i < N; i++){ //その行に候補は入るか if(sudoku[i][y] == k){ return 0; } } for(j=0; j < N; j++){ //その列に候補は入るか if(sudoku[x][j] == k){ return 0; } } p = x/M*M; q = y/M*M; //そのブロックに候補は入るか for(i = p; i < p+M; i++){ for(j = q; j < q+M; j++){ if(sudoku[i][j] == k){ return 0; } } } return 1; } int Solve(int level) //戻り値をvoidからintにしてみた。各所で戻り値を設定。 { int k; int x,y; if(level >= MTX){ printf("OK\n"); return 1; } x = level % N; y = level / N; if(sudoku[x][y] != 0){ if (Solve(level+1) == 1){ printf("skipped:%d,%d,%d\n",x,y); return 1; } }else{ for(k = 1; k <= N; k++){ if(OKkouho(x,y,k) == 1){ sudoku[x][y] = k; if(Solve(level+1) == 1){ printf("succeed:%d,%d,%d\n",x,y,k); return 1; }else{ printf("failed:%d,%d,%d\n",x,y,k); sudoku[x][y] = 0; } }else{ printf("failed:%d,%d,%d\n",x,y,k); } } return 0; } } int main(void) { //どうもsudoku[y][x]でなくsudoku[x][y]でいいっぽい。 //最初から入力データが間違っていた場合については考慮していない。 if (Solve(0) == 1){ ShowAnswer(); }else{ printf("no answer!"); } return 0; } int ShowAnswer(){ int i; int j; for (i = 0;i<N;i++){ for(j = 0;j<N;j++){ printf("%d,",sudoku[i][j]); } printf("\n"); } return 1; }

関連するQ&A

  • 数独の問題作成

    今C#で数独の問題を作成するプログラムを作ろうと思っています。 数独についてはhttp://gdb.on.arena.ne.jp/PZ/PLACE/を見てください。 まずはhttp://gdb.on.arena.ne.jp/PZ/PLACE/のルールに反しないように 9*9マスに数字を入れるプログラムを作って見たのですが途中で止まってしまいます。 途中で止まる原因がわかる方がいましたら原因を教えて下さい。 お願いします。 using System; class sudoku { Random random = new Random(); private int r; private int i, j; private int[,] X = new int[9, 9]; public sudoku() { for (i = 0; i < 9; i++) { for (j = 0; j < 9; j++) { r = random.Next(1, 10); X[i, j] = r; hikaku(); } } } public void hikaku() { while (true) { int start1 = 0, start2 = 0, end2 = 0, shoki1, shoki2, a, b,x,y,z; x = 0; y = 0; z = 0; //縦についての設定 if (i == 0 || i == 1 || i == 2) { start1 = 0; } if (i == 3 || i == 4 || i == 5) { start1 = 3; } if (i == 6 || i == 7 || i == 8) { start1 = 6; } //横についての設定 if (j == 0 || j == 1 || j == 2) { start2 = 0; end2 = 2; } if (j == 3 || j == 4 || j == 5) { start2 = 3; end2 = 5; } if (j == 6 || j == 7 || j == 8) { start2 = 6; end2 = 8; } //ループで□内を検索 for (shoki1 = start1; shoki1 <= i; shoki1++)//縦ループ { for (shoki2 = start2; shoki2 <= end2; shoki2++) { if (i == shoki1 && j == shoki2) { break; } if (X[i, j] == X[shoki1, shoki2]) { r = random.Next(1, 10); X[i, j] = r; x = 1; } } } //ここから横を比較 for (b = 0; b < j; b++) { if (X[i, j] == X[i, b]) { r = random.Next(1, 10); X[i, j] = r; y = 1; } } //ここから縦を比較 for (a = 0; a < i; a++) { if (X[i, j] == X[a, j]) { r = random.Next(1, 10); X[i, j] = r; z = 1; } } if (x == 0 && y == 0 && z == 0) { break; } } Console.Write("{0} ", X[i, j]);//途中で止まるので何処までいったかの表示用 } public void Write() { for (i = 0; i < 9; i++) { for (j = 0; j < 9; j++) { Console.Write("{0} ",X[i, j]); } Console.WriteLine(); } } static void Main() { sudoku S = new sudoku(); S.Write(); } }

  • 有限体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(); }

  • 数独解答判定プログラム

    数独の解答判定プログラムを作成しているのですが、完成しません。下に僕の作ったプログラムを載せておくので間違い等の指摘をお願いします。 #include <stdio.h> #define row 9 #define column 9 int question[row][column]={ 915284376, 273916584, 468753912, 396178245, 742365891, 851492637, 629847153, 587631429, 134529768, }; int num; int singlenumber(void); int saferow(int, int); int safecolumn(int, int); int safebox(int, int, int); int main(void){ int judge; for(num = 1; num <= 9; num++){ int singlenumber(void); } if(judge == 0){ printf("おめでとう!! 正解です。"); }else{ printf("残念!! 不正解です。"); } return 0; } int singlenumber(void){ int i, j; int row_judge; int column_judge; int box_judge; int judge; for(i = 0; i < row; i++){ int saferow(int i, int num); } for(j = 0; j < column; j++){ int safecolumn(int j, int num); } for(i = 0; i < row; i++){ for(j = 0; j < column; j++){ int safebox(int i, int j, int num); } } if(row_judge == 0 && column_judge == 0 && box_judge == 0){ judge = 0; }else{ judge = 1; } return judge; } int saferow(int i, int num){ int k; int row_judge; for(k = 0; k < column; k++){ if(num == question[i][k]){ row_judge = 0; }else{ row_judge = 1; } } return row_judge; } int safecolumn(int j, int num){ int l; int column_judge; for(l = 0; l < row; l++){ if(num == question[l][j]){ column_judge = 0; }else{ column_judge = 1; } } return column_judge; } int safebox(int i, int j, int num){ int m, n; int box_judge01, box_judge02, box_judge03; int box_judge11, box_judge12, box_judge13; int box_judge21, box_judge22, box_judge23; int box_judge0, box_judge1, box_judge2, box_judge; for(m = 0; m < row ; m++){ if(m / 3 == 0){ for(n = 0; n < 3; n++){ if(num == question[m][n]){ box_judge01 = 0; }else{ box_judge01 = 1; } } for(n = 3; n < 6; n++){ if(num == question[m][n]){ box_judge02 = 0; }else{ box_judge02 = 1; } } for(n = 6; n < 9; n++){ if(num == question[m][n]){ box_judge03 = 0; }else{ box_judge03 = 1; } } } if(box_judge01 == 0 && box_judge02 == 0 && box_judge03 == 0){ box_judge0 = 0; }else{ box_judge0 = 1; } if(m / 3 == 1){ for(n = 0; n < 3; n++){ if(num == question[m][n]){ box_judge11 = 0; }else{ box_judge11 = 1; } } for(n = 3; n < 6; n++){ if(num == question[m][n]){ box_judge12 = 0; }else{ box_judge12 = 1; } } for(n = 6; n < 9; n++){ if(num == question[m][n]){ box_judge13 = 0; }else{ box_judge13 = 1; } } } if(box_judge11 == 0 && box_judge12 == 0 && box_judge13 == 0){ box_judge1 = 0; }else{ box_judge1 = 1; } if(m / 3 == 2){ for(n = 0; n < 3; n++){ if(num == question[m][n]){ box_judge21 = 0; }else{ box_judge21 = 1; } } for(n = 3; n < 6; n++){ if(num == question[m][n]){ box_judge22 = 0; }else{ box_judge22 = 1; } } for(n = 6; n < 9; n++){ if(num == question[m][n]){ box_judge23 = 0; }else{ box_judge23 = 1; } } } if(box_judge21 == 0 && box_judge22 == 0 && box_judge23 == 0){ box_judge2 = 0; }else{ box_judge2 = 1; } if(box_judge0 == 0 && box_judge1 == 0 && box_judge2 == 0){ box_judge = 0; }else{ box_judge = 1; } } return box_judge; }

  • プログラミングのことで困っています。助けて下さい。

    プログラミングの問題がどうしても分からず、本当に困っています。 ・2x+y+3z=13 ・x+3y+2z=13 ・3x+2y+z=10 (解:x=1,y=2,z=3) を掃き出し法で解くプログラミングの問題で、次の(1)~(5)が何が当てはまるかどうしても分からないんです。 #include <stdio.h> #define N 3 /*未知数の個数*/ int main(void) { int i,j,k; double pivot,del; double a[N][n+1]={{2,1,3,13},{1,3,2,13},{3,2,1,10}}; /*係数行列*/ for(i=0;i<N;i++) { (1)____ /*ピボット係数*/ for(j=0;j<N+1;j++) /*ピボット行をピボットで割る*/ (2)____ for(k=0;k<N;k++) /*ピボット列の掃き出し*/ { if((3)____) { del=a[k][i]; for(j=i;j<N+1;j++) (4)____ } } } for(i=0;i<N;i++) (5)____ /*計算結果の表示*/ return 0; } 実行結果は x0=1.00 x1=2.00 x2=3.00 と表示させたいのですが、(1)~(5)の所がどうしても分からず、困っています。どなたか助けて下さい。お願いします。

  • Cプログラムで15パズルを作ってみたのですがうまく動作しません。何処が

    Cプログラムで15パズルを作ってみたのですがうまく動作しません。何処が間違っているのかずっと考えているのですがいまだに解決策が見つかりません。ヒントでもいいのでお願します。 #include <stdio.h> int init(void); void show(void); int chk_cmp(void); char input(void); int move(char cmd); #define N 4 int panel[N][N] = { { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9, 10, 11, 0}, {13, 14, 15, 12} }; int x, y; int main(void) { printf("これは15パズルです。\n" "左上から右に向かって「1」から「15」が並ぶよう,\n" "「0」を動かしてください。\n" "操作はテンキーで行います。( 8(上),4(左),6(右),2(下) )\n"); if( !init() ) { printf("パネルの初期化に失敗しました。「0」のパネルがありません。\n"); return 1; } while(1) { show(); if( chk_cmp() ) { printf("完成です!\n"); break; } while(1) { if( move(input()) ) { break; } else { printf("そっちには動かせません。\n"); } } } return 0; } int init(void) { int i,j; for(i=0;i<=N-1;i++){ for(j=0;j<=N-1;j++){ if(panel[i][j]==0){ x=j; y=i; return 1; } } } return 0; } void show(void) { int i,j; printf("---------------\n"); for(i=0;i<=N-1;i++){ for(j=0;j<=N-1;j++){ printf("%3d",panel[i][j]); } printf("\n"); } printf("---------------\n\n"); } int chk_cmp(void) { int i,j; for(i=0;i<=N-1;i++){ for(j=0;j<=N-1;j++){ if(i==N-1&&j==N-1){ if(panel[i][j]!=0){ return 0; } }else{ if(panel[i][j]!=N*i+j+1){ return 0; } } } } return 1; } char input(void) { int comand; while(1){ scanf("%d",&comand); if(comand==8||comand==4||comand==6||comand==2){ break; } printf("8(上),4(左),6(右),2(下)を入力してください。"); } return comand; } int move(char cmd) { int dx=0, dy=0; if(cmd==8){dy=-1;}//上 if(cmd==4){dx=-1;}//左 if(cmd==6){dx=1;}//右 if(cmd==2){dy=1;}//下 if(x+dx>=0&&x+dx<=N-1&&y+dy>=0&&y+dy<=N-1){ panel[y][x]==panel[y+dy][x+dx]; panel[y+dy][x+dx]==0; y+=dy; x+=dx; return 1; } else{return 0;} }

  • 行列の計算

    #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++でグラフをリスト構造で作る

    今、『グラフのデータを読み込んで、行列形式で配列に保存するプログラム』を作りました。下記に私の作ったそのプログラムがあります。しかしこの次にこれと同じことを「リスト構造」を使って作らないといけないのですがなかなかうまくいかないです。どのように作ればいいか分かる人がいたら教えてください! #include<stdio.h> #define hairetu 5 int main(void){ int x, y, i, j, a[hairetu][hairetu]; for(i=0; i<5; i++){ for(j=0; j<5; j++){ a[i][j]=0; } } printf("0以下の数を入れると終了します\n"); while(1){ printf("1~5の数のうち、2つ数字を入力しなさい\n"); scanf("%d%d", &x, &y); if(x<=0 || y<=0){ break; } else if(x>5 || y>5){ printf("エラー\n"); return 1; } a[x-1][y-1]=1; } for(i=0; i<5; i++){ printf("\n"); for(j=0; j<5; j++){ printf("%d", a[j][i]); } } printf("\n"); return 0; }

  • 設定した値が意図せぬ値に

    POJ 3176の問題です。 http://poj.org/problem?id=3176 #include <iostream> #include <algorithm> #define MAX 100 using namespace std; int main() { int n; cin >> n; int line[n-1][MAX]; int num[n-1][MAX]; cin >> line[0][0]; if(n==0) { cout << 0 <<endl; return 0; } else if(n==1) { cout << line[0][0] << endl; return 0; } for (int i =1;i < n;i++) { for (int j=0;j < i+1;j++) { int x; cin >> x; line[i][j]= x; } } for (int k= 0 ; k<n;k++) { num[n-1][k]= line [n-1][k]; } for (int k= n-2; k > 0 ; k--) { for (int l=0 ; l<k+1; l++) { num[k][l] = max (num[k+1][l],num[k+1][l+1]) + line[k][l]; } } num[0][0] = max(num[1][0],num[1][1]) + line[0][0]; cout << line[0][0] <<" "<<num[0][0]<<endl; return 0; } 入力 4 3 1 3 1 2 3 1 3 4 5 出力 1 12 最後に出力でline[0][0]をするようにしているのはバグチェックのためです。 ここで僕がわからないのはどうしてline[0][0]が3で宣言し、ほかでいじっていないにも関わらず、最後に1になっているのかということです。 どなたかわかる方がいらっしゃったらよろしくお願いします。

  • 座標をランダムに表示させてx座標順にソートするプログラムを考えています

    座標をランダムに表示させてx座標順にソートするプログラムを考えています とりあえず、以下の様に決まった数の座標でソートすることはできたのですが、ランダムにするとなるとどうすればいいのかわかりません。 ------------------------------------------------- #include <stdio.h> int makepoints(int * pn, double * x, double * y){ double xp,yp; int k; int i,j; int n; n = 7; *pn = n; xp = 1; for(k=0;k<n;k++) { xp = xp/2; yp = xp*xp; x[k] = xp; y[k] = yp; } printf("初期座標列:\n"); for(k=0;k<n;k++) { printf("%f_%f\n",x[k],y[k]); } for(j=1;j<n;j++) { for(i=0;i<j;i++) { if(x[i]>x[j]){ xp=x[i];x[i]=x[j];x[j]=xp; yp=y[i];y[i]=y[j];y[j]=yp; } } } printf("整列後の座標列:\n"); for(k=0;k<n;k++) { printf("%d %f %f\n",k ,x[k],y[k]); } return 0; } ------------------------------------------------- なんとなくrand関数を使えばいいのかな、というのはわかるのですが、プログラミングに弱く困っています。 この後のプログラミング教えてくださる方いればよろしくお願いします。

  • すいません。。改めて質問!!

    #include<stdio.h> #define NMAX 200 int n; int a[NMAX], x[NMAX]; void yomikomi() { for(n=0; scanf("%d%d",&a[n],&x[n])!=EOF;n++); return; } void hyouzi() { int i; for(i=0;i<n;i++) printf("%5d %5d\n",a[i],x[I]); return; } void seiretu() { int i,j,max,k,w; for(i=0;i<n-1;i++){ max=x[i];k=i; for(j=i+1;j<n;j++) if(x[j]>max){ max=x[j];k=j; } w=a[k];a=[k]=a[i];a[i]=w; x[k]=x[i]; x[i]=max; } return; } main() { printf("sorting\n"); yomikomi(); printf(\nInput data\n"); hyouzi(); seiretu(); printf(\nSorted data\n); hyouzi(); return(0); } これを改良して偶数と奇数に分けてソートするプログラムがわかればいいのですが。。まだ慣れないものですいませんでした。

専門家に質問してみよう