递归数独求解器几乎可以工作,但空网格的堆栈溢出
Recursive Sudoku solver almost working but getting stack overflow for empty grid
我正在尝试通过递归来解决数独问题。该程序运行良好。问题是堆栈只能保持 4-6K 递归。这意味着,如果我离开 soduku 时有超过 6-7 个空单元格,解决它所需的组合是:
4^7 = 16384 > 4-5K...
如何改进我的程序以使用更少的呼叫?该程序可以很好地解决此问题。该函数:
void solve_soduku(int soduku[][N*N], int &row, int &col, const bool fix_v[][N*N])
是所有的业务。
我在这里为您提供正确 soduku 所需的所有数字,以免浪费您的时间。你可以把它们中的一些拿出来,看看它是如何工作的:
0 0 1
0 1 2
0 2 3
0 3 4
1 0 4
1 1 3
1 2 2
1 3 1
2 0 3
2 1 1
2 2 4
2 3 2
3 0 2
3 1 4
3 2 1
3 3 3
-1
和代码:
#include <iostream>
using namespace std;
const int N = 2;
void zero_soduku(int soduku[][N*N]);
void zero_arr(int temp_arr[], int size);
void get_input(int soduku[][N*N], bool fixed_values[][N*N]);
void solve_soduku(int soduku[][N*N], int &row, int &col, const bool fix_v[][N*N]);
bool check_soduku(const int soduku[][N*N]);
bool check_rows(const int soduku[][N*N]);
bool check_cols(const int soduku[][N*N]);
bool check_sub_interval(const int soduku[][N*N]);
void print_soduku(const int soduku[][N*N]);
int main() {
int soduku[N*N][N*N] = { 0 }, row = 0, col = 0;
bool fixed_values[N*N][N*N] = { false };
get_input(soduku, fixed_values);
solve_soduku(soduku, row, col, fixed_values);
cout << endl;
print_soduku(soduku);
system("pause");
return EXIT_SUCCESS;
}
bool check_soduku(const int soduku[][N*N]) {
if (check_rows(soduku) && check_cols(soduku) && check_sub_interval(soduku))
return true;
return false;
}
bool check_rows(const int soduku[][N*N]) {
int temp_arr[N*N] = { 0 };
for (auto i = 0; i < N*N; i++) {
zero_arr(temp_arr, N*N);
for (auto j = 0; j < N*N; j++)
temp_arr[soduku[i][j] - 1]++;
for (auto k = 0; k < N*N; k++)
if (temp_arr[k]>1)
return false;
}
return true;
}
bool check_cols(const int soduku[][N*N]) {
int temp_arr[N*N] = { 0 };
for (auto i = 0; i < N*N; i++) {
zero_arr(temp_arr, N*N);
for (auto j = 0; j < N*N; j++)
temp_arr[soduku[j][i] - 1]++;
for (auto k = 0; k < N*N; k++)
if (temp_arr[k]>1)
return false;
}
return true;
}
bool check_sub_interval(const int soduku[][N*N]) {
int temp_arr[N*N] = { 0 };
for (auto rows_intervals = 0; rows_intervals < N; rows_intervals++)
for (auto cols_intervals = 0; cols_intervals < N; cols_intervals++)
for (auto i = rows_intervals*N; i < rows_intervals*N + N; i++)
for (auto j = cols_intervals*N; j < cols_intervals*N + N; j++) {
temp_arr[soduku[i][j] - 1]++;
//end of interval, check if !good interval
if (i == rows_intervals*N + N - 1 && j == cols_intervals*N + N - 1) {
for (auto k = 0; k < N*N; k++)
if (temp_arr[k]>1)
return false;
zero_arr(temp_arr, N*N);
}
}
return true;
}
void solve_soduku(int soduku[][N*N], int &row, int &col, const bool fix_v[][N*N]) {
static int counter = 0;
counter++;
cout << endl << counter << endl;
//Not empty cell
if (soduku[row][col] != 0)
//Not end of line
if (col < N*N - 1) {
col++;
solve_soduku(soduku, row, col, fix_v);
}
else
//Not end of rows
if (row < N*N - 1) {
row++;
col = 0;
solve_soduku(soduku, row, col, fix_v);
}
else
//end of soduku
if (check_soduku(soduku)) {
print_soduku(soduku);
return;
}
/////// Finishd soduku but answaer not good //////////////////
else
//Last cell not max
if (soduku[row][col] < N*N - 1) {
soduku[row][col]++;
print_soduku(soduku);
cout << endl;
solve_soduku(soduku, row, col, fix_v);
}
//Last cell max, going back...
else {
while (soduku[row][col] == N*N || fix_v[row][col]) {
if (!fix_v[row][col]) {
soduku[row][col] = 1;
print_soduku(soduku);
cout << endl;
}
if (col > 0) {
col--;
continue;
}
if (col == 0 && row > 0) {
col = N*N - 1;
row--;
}
}
if (!fix_v[row][col]) {
soduku[row][col]++;
print_soduku(soduku);
cout << endl;
}
solve_soduku(soduku, row, col, fix_v);
}
//////////////////////////////////////////////////////////////////////////
//Empty cell
else {
soduku[row][col]++;
print_soduku(soduku);
cout << endl;
solve_soduku(soduku, row, col, fix_v);
}
}
void zero_arr(int temp_arr[], int size) {
for (auto i = 0; i < size; i++)
temp_arr[i] = 0;
}
void zero_soduku(int soduku[][N*N]) {
for (int i = 0; i < N*N; i++)
for (int j = 0; j < N*N; j++)
soduku[i][j] = 0;
}
void get_input(int soduku[][N*N], bool fixed_values[][N*N]) {
cout << endl << "Please enter locatin and nums into soduku: ";
int row = 0, col, value;
while (row != -1) {
cin >> row;
if (row == -1)
return;
cin >> col >> value;
soduku[row][col] = value;
fixed_values[row][col] = true;
}
}
void print_soduku(const int soduku[][N*N]) {
for (auto i = 0; i < N*N; i++)
for (auto j = 0; j < N*N; j++) {
cout << soduku[i][j] << " ";
if (j == N*N - 1)
cout << endl;
}
//system("pause");
}`enter code here`
你的算法看起来大致是:
1)依次尝试每个动作
2)检查整个电路板,看看它是否有效
3) 重复直到整个板子填满
这显然效率很低。该代码将做出许多非法的举动,然后只是在事后才意识到这一点。
我建议你完全摆脱它,并尝试实现一些更有效的东西。尝试思考碳基生命形式如何解决数独难题,并实现相同的算法。当你解决数独谜题时,你也做上述方法吗?当然不是。你做这样的事情:
1)对于董事会上的每个位置,不仅存储该位置的当前数字(如果有),还存储附加信息:即,如果该位置没有数字,还要存储所有可能的数字,这些数字将使该位置合法移动。
例如,对于一个完全空的棋盘,数独棋盘上的每个位置都将包含所有值 1-9。由此,我们进行下一个合乎逻辑的步骤:
2)移动并将值放置在某个位置(例如4)时,您将从其4x3正方形中的所有其他单元格中删除值3,并从同一行和列中的所有其他单元格中删除4。因为该数字将不再是这些单元格中的有效移动。相反,当撤消移动并从单元格中删除 4 时,这意味着值 4 现在在其 3x3 正方形的所有单元格及其行和列中都是合法的,因此您可以将此值放在所有这些位置,作为一个数字,现在是这些位置的合法移动。
3)在决定下一步行动时,首先扫描电路板,寻找只有一个可能的合法号码的任何单元格。当然,这意味着这是该细胞的唯一合法举措,所以你做到了。
4)如果您发现任何没有合法值的单元格,这意味着您达到了无法解决的状态,因此您将撤消上次移动,然后从该点开始尝试下一个有效移动。
5)否则,你应该选择一个可能合法移动最少的单元格,进行第一个移动,然后继续前进,然后如果你达到无法解决的状态,并返回这个移动,你撤消它,并尝试下一步。
在我看来,这种方法应该更有效,因为它最终应该做出最少的非法举动。
它也非常模仿碳基生命形式如何自己解决数独难题。
附言要使用预填充的数字初始化新的数独拼图,只需从一个空的数独板开始,所有单元格都允许所有数字 1-9 作为合法移动,然后如上所述进行每次移动以填充数独板上的初始数字。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 找出一个正方形逻辑中可能的网格数量,但代码不接受超过六个输入,它停止并说.exe停止工作
- 递归数独求解器几乎可以工作,但空网格的堆栈溢出