生成数独难题

时间:2019-12-06 14:40:44

标签: c algorithm backtracking sudoku

我正在尝试编写一段代码,为我生成一个有效的数独难题。

我的算法:

  1. 使用0初始化所有字段
  2. 遵守规则并将1-9中的20个随机值设置为随机字段
  3. 使用反向跟踪算法解决难题

我的问题:

  1. 有时它会在1秒内生成一个有效的数独谜题。
  2. 有时它无法生成有效的数独,并且出现错误,这是可以的,因为我可以返回算法的第1步。
  3. 有时它无法生成有效的数独,但我收到一个错误,但大约需要2-3分钟,这是不正确的。

我该如何解决我的问题? 特别是问题3。 我可以只计算秒数,如果要花费5秒以上的时间,请返回算法的第1步?

还是有人有更好的主意?

提前谢谢。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>

#define N 9
#define UNASSIGNED 0


typedef enum {false, true} bool;
typedef struct { 
    char number;
    bool editable; 
} GRID;

void print_sudoku(GRID **g){
    char row=0, col=0;
    for(row=0; row<N; row++){
        for(col=0; col<N; col++){
            printf("%d ", g[row][col].number);
        }
        printf("\n");
    }
}


GRID ** create_sudoku_grid(){
    char i, row, col;
    GRID **g = (GRID **) malloc(N * sizeof(GRID *));
    for (i=0; i<N; i++) {
        g[i] = (GRID *) malloc(N * sizeof(GRID)); 
    }

    for(row=0; row<N; row++){
        for(col=0; col<N; col++){
            g[row][col].number = UNASSIGNED;
            g[row][col].editable = true;
        }
    }
    return g;
}



bool find_unassigned_field(GRID **g, int *row, int *col){
    for (*row = 0; *row < N; (*row)++) {
        for (*col = 0; *col < N; (*col)++) { 
            if (g[*row][*col].number == UNASSIGNED){
                return true;    
            } 
        }
    }
    return false; 
}

bool validate_row(GRID **g, int row, int num) { 
    for (int col = 0; col < N; col++) {
        if (g[row][col].number == num) {
            return false; 
        }
    }
    return true; 
} 

bool validate_col(GRID **g, int col, int num) { 
    for (int row = 0; row < N; row++) {
        if (g[row][col].number == num) {
            return false; 
        }
    }
    return true; 
} 


bool validate_box(GRID **g, int row, int col, int num) { 
    for (int r = 0; r < 3; r++) {
        for (int c = 0; c < 3; c++) { 
            if (g[r+row][c+col].number == num) {
                return false; 
            }
        }
    }
    return true; 
} 


bool validate_field(GRID **g, int row, int col, int num){
    bool valrow, valcol, valbox, valunassigned;

    valrow = validate_row(g, row, num); 
    valcol = validate_col(g, col, num);
    valbox = validate_box(g, row - row%3 , col - col%3, num);
    valunassigned = g[row][col].number==UNASSIGNED; 
    return (valrow && valcol && valbox && valunassigned);

}


bool generate_sudoku(GRID **g) { 
    int row, col; 

    // If there is no unassigned location, we are done 
    if (!find_unassigned_field(g, &row, &col)) {
        return true; // success! 
    }

    // consider digits 1 to 9 
    for (int num = 1; num <= 9; num++) { 
        // if looks promising 
        if (validate_field(g, row, col, num)) { 
            // make tentative assignment 
            g[row][col].number = num; 

            // return, if success, yay! 
            if (generate_sudoku(g)) {
                return true; 
            }
            // failure, unmake & try again 
            g[row][col].number = UNASSIGNED; 
        } 
    } 
    return false; // this triggers backtracking 
} 

void random_init_grid(GRID **g){
    int row, col, num;
    srand(time(0));

    for(int cntr=0; cntr<20;){
        row = rand() % N;
        col = rand() % N;
        num = rand() % N + 1;
        if(g[row][col].number == UNASSIGNED){
            if(validate_field(g, row, col, num)){
                g[row][col].number = num;
                cntr++;
            }
        }

    }
}

int main(int argc, char *argv[]) {
    GRID **g = create_sudoku_grid();
    random_init_grid(g);

    if(generate_sudoku(g)){
        printf("OK\n\n");
    } else {
        printf("\nNOT OK\n\n");
    }
    print_sudoku(g);
}

1 个答案:

答案 0 :(得分:0)

Sudoko是一个计算难题,使用蛮力和无知可能约为10 ^ 100。可能需要超过2-3分钟的时间!有时,由于数字布局,比这容易得多。

在一种方法中,您可以计算迭代次数,如果迭代次数超过迭代次数则放弃。您的关键位是递归调用generate_soduko()的块-如果您在此结束的次数过多,则有麻烦。

为此,我更改了您的程序的执行时间,并向其发出1s警报,以计数该块中的次数;如果警报到期,则打印计数器并退出;如果没有在最后打印计数器以供参考。在我的机器上,1s == 500,000次迭代。

*** sud.c~  2019-12-06 14:30:21.000000000 -0500
--- sud.c   2019-12-06 14:30:57.000000000 -0500
***************
*** 1,10 ****
  #include <stdio.h>
  #include <stdlib.h>

  #define N 9
  #define UNASSIGNED 0

- 
  typedef enum {false, true} bool;
  typedef struct { 
      char number;
--- 1,21 ----
  #include <stdio.h>
  #include <stdlib.h>
+ #include <signal.h>
+ #include <unistd.h>
+ #include <time.h>
+ 
+ volatile long  counter;
+ void alrm(int signo) {
+   char buf[64];
+   int n;
+   n = sprintf(buf, "failed after %ld iter\n", counter);
+   write(2, buf, n);
+   _exit(1);
+ }

  #define N 9
  #define UNASSIGNED 0

  typedef enum {false, true} bool;
  typedef struct { 
      char number;
***************
*** 106,111 ****
--- 117,123 ----
      for (int num = 1; num <= 9; num++) { 
          // if looks promising 
          if (validate_field(g, row, col, num)) { 
+       counter++;
              // make tentative assignment 
              g[row][col].number = num; 

***************
*** 139,145 ****
  }

  int main(int argc, char *argv[]) {
!     GRID **g = create_sudoku_grid();
      random_init_grid(g);

      if(generate_sudoku(g)){
--- 151,161 ----
  }

  int main(int argc, char *argv[]) {
! 
!     GRID **g;
!   signal(SIGALRM, alrm);
!   alarm(1);
!     g = create_sudoku_grid();
      random_init_grid(g);

      if(generate_sudoku(g)){
***************
*** 148,151 ****
--- 164,168 ----
          printf("\nNOT OK\n\n");
      }
      print_sudoku(g);
+     printf("iter = %ld\n", counter);
  }