如何解决数独问题,以便通过交换任何两个相邻的子网格,我仍然得到有效的答案?

How to solve a sudoku such that by swapping any two adjacent sub grids I still get a valid answer?

本文关键字:网格 答案 有效 交换 解决 何解决 问题 任何两      更新时间:2023-10-16

我得到了一个n^2 * n^2网格,里面填充了几个数字。我需要使用基本的数独规则以及另一个附加条件来填充剩余的网格,即确保如果我交换任何 2 个相邻的子网格 (n*n),那么我的整体网格(数独)仍然有效。我正在使用回溯技术来解决它。但我无法满足附加条件。

1 2 | 3 4
3 4 | 1 2
---------
2 1 | 4 3
4 3 | 2 1
2 1 | 3 4
4 3 | 1 2
---------
1 2 | 4 3
3 4 | 2 1

在这里,将左上角的框与左下角的框交换在一起,我仍然得到了答案。同样,如果我们并排或顶部和底部交换任何盒子(如果它们是相邻的),应该是可能的。

请帮助我。以下是从 www.geeksforgeeks.org 中获取的回溯方法的代码

bool SolveSudoku(int grid[N][N])
{
int row, col;
if (!FindUnassignedLocation(grid, row, col))
return true;
for (int num = 1; num <= 9; num++)
{
if (isSafe(grid, row, col, num))
{
grid[row][col] = num;
if (SolveSudoku(grid))
return true;
grid[row][col] = UNASSIGNED;
}
}
return false; // this triggers backtracking
}
bool FindUnassignedLocation(int grid[N][N], int &row, int &col)
{
for (row = 0; row < N; row++)
for (col = 0; col < N; col++)
if (grid[row][col] == UNASSIGNED)
return true;
return false;
}
bool UsedInRow(int grid[N][N], int row, int num)
{
for (int col = 0; col < N; col++)
if (grid[row][col] == num)
return true;
return false;
}
bool UsedInCol(int grid[N][N], int col, int num)
{
for (int row = 0; row < N; row++)
if (grid[row][col] == num)
return true;
return false;
}
bool UsedInBox(int grid[N][N], int boxStartRow, int boxStartCol, int num)
{
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++)
if (grid[row+boxStartRow][col+boxStartCol] == num)
return true;
return false;
}
bool isSafe(int grid[N][N], int row, int col, int num)
{
return !UsedInRow(grid, row, num) &&
!UsedInCol(grid, col, num) &&
!UsedInBox(grid, row - row%3 , col - col%3, num);
}
void printGrid(int grid[N][N])
{
for (int row = 0; row < N; row++)
{
for (int col = 0; col < N; col++)
printf("%2d", grid[row][col]);
printf("n");
}
}

我如何将该条件合并到其中。首先,请让我知道是否有可能通过回溯来解决。"n"的上限是 30。

给定一个有效的数独解决方案,以及其中两个子网格AB,一个在另一个之上(除了另一个),当且仅当它们在每行(resp.columns)上具有相同的元素(以不同的顺序)时,您可以交换AB。(即sort(A[i, :])==sort(B[i, :]1..n 中的所有 i)。

因此,您需要做的就是添加一些约束,以反映这一点:

  • 当您想将值a放在A[i, j]中时(A子网格),请考虑A的邻居。给定一个B高于或低于A的邻居,如果a已经在B中,则移动无效
  • ,与i行不同
  • 同样适用于 A 的水平邻居(带列)

因此,在实践中,您只需要使用更多约束来扩展isSafe():)。

它实际上应该比没有 n 的大值约束的运行速度更快,因为您将探索更少的树。

编辑

我会添加函数 UsedInNeighborsWrongRow(rep. 列),例如:

bool UsedInNeighborsWrongRow(int grid[N][N], int boxStartRow, int boxStartCol, int rowIdw, int num) 
{
for (int row = 0; row < N; row++)
if (row != rowIdx)
for (int col = 0; col < N; col++)
if (grid[row+boxStartRow][col+boxStartCol] == num)
return true;    
return false;
}

并在isSafe中为每个邻居打电话给他们:

bool isSafe(int grid[N][N], int row, int col, int num)
{
bool OKForSwapping = !UsedInNeighborsWrongRow(grid, neighbor1_row, neighbor1_col, row, num);
if (there is a 2nd vertical neighbor) 
OKForSwapping &=!UsedInNeighborsWrongRow(grid, neighbor2_row, neighbor2_col, row, num);
OKForSwapping &=!UsedInNeighborsWrongColumn(grid, neighbor3_row, neighbor3_col, col, num);
if (there is a 2nd horizontal neighbor) 
OKForSwapping &=!UsedInNeighborsWrongColumn(grid, neighbor4_row, neighbor4_col, row, num);
return !UsedInRow(grid, row, num) &&
!UsedInCol(grid, col, num) &&
!UsedInBox(grid, row - row%N , col - col%N, num) &&
OKForSwapping;
}

它很长,但我不确定你能做得更好,数独结构更适合其他约束,而不是这个......

警告:您应该在函数UsedInBoxisSafe中将 3 替换为 N