【发布时间】:2019-12-06 14:40:44
【问题描述】:
我正在尝试编写一段代码,为我生成一个有效的数独游戏。
我的算法:
- 用 0 初始化所有字段
- 遵守规则,将 1-9 的 20 个随机值设置为随机字段
- 使用回溯算法解决难题
我的问题:
- 有时它会在 1 秒内生成一个有效的数独游戏。
- 有时它无法生成有效的数独并且我得到一个错误,这没关系,因为我可以返回算法中的第 1 步。
- 有时它无法生成有效的数独,我得到一个错误,但它需要大约 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);
}
【问题讨论】:
-
你可以这样做,是的。
-
您的算法是否检查是否存在只有一个可能的解决方案?
-
你有没有调查过你的算法的哪一部分是慢的?回溯搜索是否有时需要很长时间,或者是因为您生成了大量网格而被拒绝,因为它们没有解决方案(或多个解决方案)?
-
欢迎来到 StackOverflow。见minimal, reproducible example。在您发布 MRE 代码并准确说明问题之前,我们无法有效地帮助您。我们应该能够将您发布的代码粘贴到文本文件中并重现您指定的问题。我不明白#1 是怎么回事;你说#2没问题。您确实不为#3 给出了可重现的问题。代替随机化,硬编码一个给你这个问题的起始网格。跟踪代码中的慢点。 那么你的帖子很好。
-
OT:发布的代码动态分配数组数组来存储大小为 N 的网格,这是一个在编译时已知的常数。您可以将该网格声明为
GRID g[N][N]并传递一个指针GRID g[][N]。
标签: c algorithm backtracking sudoku