![](/img/trans.png)
[英]I am having trouble with my recursive backtracking algorithm for solving sudoku in C
[英]Recursive Backtracking Algorithm in C to solve a Sudoku
我必须在sudoku.c中实现大学的递归求解方法。
我尽力了,但是所有的实现都没有用。
我是编程c的绝对新手,因此我对使用此Sudoku回溯算法很失望。
有人可以帮我吗?
Solve方法是空的,因此此方法中的所有内容都由我尝试。
sudoku.h
#ifndef _SUDOKU_H_
#define _SUDOKU_H_
#define SIZE 9
#define SQRT_SIZE 3
void init(int begin[SIZE][SIZE]);
void print();
int checkValueInField(int value, int row, int col);
int setValueInField(int value, int row, int col);
int removeValueFromField(int row, int col);
int getValueFromField(int row, int col);
int solve(int row, int col);
#endif /* _SUDOKU_H_ */
sudoku.c
#include "sudoku.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define SIZE 9
#define SQRT_SIZE 3
int field[SIZE][SIZE];
int initial[SIZE][SIZE];
/* Initializes the sudoku array.
* The field initial keeps the original start value for
* figuring out if a value is fixed or can be changed. */
void init(int begin[SIZE][SIZE]) {
memcpy(field, begin, SIZE * SIZE * sizeof(int));
memcpy(initial, begin, SIZE * SIZE * sizeof(int));
}
/* really pretty prints the sudoku array */
void print() {
int row, col;
// print the first line
printf("||");
for (col = 0; col < SIZE - 1; col++) {
if (col % SQRT_SIZE == SQRT_SIZE - 1)
printf("===++");
else
printf("===+");
}
printf("===||\n");
// loop through all rows of the array
for (row = 0; row < SIZE; row++) {
// print the line with field values
for (col = 0; col < SIZE; col++) {
if (col % SQRT_SIZE == 0)
printf("|| ");
else
printf("| ");
if (field[row][col] == 0)
printf(" ");
else
printf("%d ", field[row][col]);
}
// print the separation line;
// depending on the result of the modulo operation
// print a single or double line
printf("||\n||");
if (row % SQRT_SIZE == SQRT_SIZE - 1) {
for (col = 0; col < SIZE - 1; col++) {
if (col % SQRT_SIZE == SQRT_SIZE - 1)
printf("===++");
else
printf("===+");
}
printf("===||\n");
}
else {
for (col = 0; col < SIZE - 1; col++) {
if (col % SQRT_SIZE == SQRT_SIZE - 1)
printf("---++");
else
printf("---+");
}
printf("---||\n");
}
}
}
/* Checks if the value is valid and can be set into the field.
* The function returns false if the value is already present or
* has been one of the initial values. */
int checkValueInField(int value, int row, int col) {
int i, r, c;
int squareRow;
int squareCol;
// checks for initial values
if (initial[row][col] != 0) {
if (initial[row][col] == value)
return 1;
else
return 0;
}
// check horizontally
for (i = 0; i < SIZE; i++) {
if (field[row][i] == value) return 0;
}
// check vertically
for (i = 0; i < SIZE; i++) {
if (field[i][col] == value) return 0;
}
// check square
squareRow = row / SQRT_SIZE;
squareCol = col / SQRT_SIZE;
for (r = squareRow * SQRT_SIZE; r < squareRow * SQRT_SIZE + SQRT_SIZE; r++) {
for (c = squareCol * SQRT_SIZE; c < squareCol * SQRT_SIZE + SQRT_SIZE; c++) {
if (field[r][c] == value) return 0;
}
}
return 1;
}
/* Set a value in the sudoku field if the field is empty.
* The method returns false if the field contains a fixed number. */
int setValueInField(int value, int row, int col) {
if (initial[row][col] == 0) {
field[row][col] = value;
return 1;
}
else if (initial[row][col] == value)
return 1;
return 0;
}
/* Removes a value in the sudoku field if it doesn't contain an initial value.
* The method returns false if the field contains a fixed number and cannot be
* removed. */
int removeValueFromField(int row, int col) {
if (initial[row][col] == 0) {
field[row][col] = 0;
return 1;
}
return 0;
}
/* Returns the value in the field */
int getValueFromField(int row, int col) {
return field[row][col];
}
/* Return true if you've found a valid solution for the sudoku. Use the
* return value to abort the backtracking algorithm if you've found the
* first solution, otherwise you would search for a possible solution. */
int solve(int row, int col) {
/* Implement a backtracking for solving the sudoku */
for (int i = 1; i <= 9; i++) {
if ((checkValueInField(i, row, col)) == 1) {
setValueInField(i, row, col);
}
solve(row, col + 1);
solve(row + 1, col);
}
return 0;
}
main.c中
#include <stdio.h>
#include "sudoku.h"
int main(int argc, char * const argv[]) {
int initial[SIZE][SIZE] = {
{0, 1, 0, 0, 0, 9, 0, 5, 0},
{0, 9, 0, 0, 0, 0, 4, 8, 0},
{0, 6, 0, 1, 0, 4, 0, 0, 0},
{0, 0, 5, 0, 0, 0, 9, 3, 0},
{0, 0, 0, 7, 0, 2, 0, 0, 0},
{0, 2, 1, 0, 0, 0, 8, 0, 0},
{4, 0, 0, 0, 8, 0, 6, 0, 9},
{0, 0, 0, 0, 6, 0, 5, 0, 3},
{2, 0, 0, 0, 3, 0, 0, 0, 0},
};
init(initial);
print();
solve(0, 0);
print();
return 0;
}
您可能想看看什么是回溯算法
您的求解将是一次求解一个位置(按row和col跟踪),然后递归检查求解下一个位置。
因此,您的求解功能至少应遍历整个网格
int solve(int row, int col) {
// solve next column in the current row
return solve(row, col + 1);
}
如您所见,问题变成了col会无限增长而无需检查其他行。 (顺便说一下,C中数组的第一个元素的索引为0)
因此,一旦到达这一行的末尾,我们就需要移至另一行(假设END_COLUMN_INDEX
包含最后一列的索引)
if(col == END_COLUMN_INDEX) { // we just reached the end of the current row
return solve(row+1, 0); // solve the beginning of the next row
}
现在您的求解将自动移至下一行,但是当我们到达最后一行时该END_ROW_INDEX
(假设END_ROW_INDEX
包含END_ROW_INDEX
的索引)
if((col == END_COLUMN_INDEX) && (row == END_ROW_INDEX)) { // we reached the end of the grid meaning that we might have successfully solved the whole grid
return 1; // return true
}
现在讲解应该执行的步骤。
solve(0,0) -> solve(0,1)
solve(0,1) -> solve(0,2)
solve(0,2) -> solve(0,3)
...
solve(0,END_COLUMN_INDEX - 1) -> solve(0, END_COLUMN_INDEX)
solve(0, END_COLUMN_INDEX) -> solve(1, 0)
...
...
solve(END_ROW_INDEX , END_COLUMN_INDEX - 1) -> solve(END_ROW_INDEX , END_COLUMN_INDEX) -> return true
(the true value is returned through each upper level of recursion)
我们现在以递归方式遍历网格
对于您需要检查的每个单元格
solve
下一个单元格) checkValueInField
1到9): setValueInField
)并尝试solve
下一个单元格 这意味着递归的上层是错误的,因此solve函数将返回false
来传达前一个单元格中的值是错误的(上层将在步骤1或3处)
测试如何solve
返回下一个单元格(在步骤1或3处)
solve
的值,我们可能想尝试其他值(回溯)。 当将false
返回到递归的上限值时,您一定不要忘记将当前单元格的值恢复为其原始值( removeValueFromField
)。
此时,您应该拥有所有指南来解决问题并编写递归数独解决功能。
另外,互联网上充满了数独解决代码的绝佳示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.