问题描述
我的挑战是通过递归和回溯来解决给定的数独领域。我们已经有了一些代码,但我们不知道如何实现回溯。这是我们的代码:
int solve( int row,int col ) {
if (getValueFromField(row,col) != 0) {
if (col < 8) {
return solve(row,col + 1);
}
if (col == 8) {
return solve(row + 1,0);
}
if (col == 8 && row == 8) {
return 1;
}
} else {
for (int i = 1; i <= 9; i++) {
if (checkValueInField(i,row,col)) {
setValueInField(i,col);
if (solve(row,col)) {
continue;
}
return solve(row,col + 1);
}
}
removeValueFromField(row,col);
return 0;
}
return -1;
}
removeValueFromField()
、setValueInField()
等方法自行解释。如果没有,我可以向您解释他们是做什么的。
您知道如何在此处实施回溯吗? 问候! 拉斐尔
解决方法
您必须保存之前所做的检查,例如在列表中 每个单元格的可能值。最初,所有列表都包含 数字 1-9。初始化时,给定的列表 数独中的单元格减少到一个成员。
然后,主要算法是对所有单元格的循环,您可能会实现它 作为递归,就像在您的代码中一样。在这个循环中所有数独约束 应用于每个列表,并删除不兼容的情况。 例如:假设 cell(1,1) 是 '1',那么我们可以从第 1 行第 1 列的所有列表中删除 1, 阻止(1,1)等。我们循环直到没有不兼容的情况。 如果列表之一折叠到零长度,则数独无法解决。
如果此时 (A) 两个或多个列表的长度保持大于 1,我们 选择这些列表之一的可能性之一(比如 p),然后开始 再次循环。如果结果无法解决,我们从列表中删除 p, 回到(A)(这是回溯)并尝试第二种可能性,依此类推。 最终,我们将达到一个阶段,除了一个列表之外,所有列表的长度为 1。 数独是可解的,如果最后一个列表的长度 > 0。
这是一个简化版本,它只是找到了一种可能的解决方案。 您必须自己编写原型函数。
int getListLength(row,col); // number of possible values for this cell,0...9
void checkConstrains(); // loop all sets (rows,columns,blocks)
// and find lists with one element. Remove
// this element from all other lists in the set.
// Repeat until no duplicates are found.
int *savelist(row,col); // make a copy of the list
void setlist(row,col,k); // set list of cell to { k }
getstate(),setstate(s); // save and set state of the game,ie. all lists
int solve( int row,int col ) {
int length = getListLength(row,col);
if(length == 0)
return 0; // unsolveable
// this is your recursion step slightly
// reordered to avoid row-overflow
if (col == 8 && row == 8) {
return 1;
}
int next_row,next_col;
if(col < 8) {
next_row = row;
next_col = col + 1;
} else {
next_row = row + 1;
next_col = 0;
}
if(length == 1) {
return solve(next_row,next_col);
}
// if we reach this step: length > 1
checkConstrains();
// length might have changed
length = getListLength(row,col);
if(length == 0)
return 0;
if(length == 1)
return solve(next_row,next_col);
// still: length > 1
// backtracking stage
int* list = savelist(row,col);
sudoku s = getstate();
for(int i = 0; i < length; i++) {
setstate(s);
setlist(row,list[i]);
if(solve(row,col))
return 1;
}
// all elements from list failed-->unsolveable
// free list and s
return 0;
}