leetcode 37 数独问题的解答
1.问题 请写一个程序来解决数独难题。
数独解决方案应该遵循以下三个规则:
1.每个数字1-9只能在每行中出现一次。
2.每个数字1-9只能在每列中出现一次。
3.每个数字1-9只能在网格的每个3x3子框中出现一次。
2.要求
·空格字符表示一个空的单元格。
·拼图板是一个长度为9的方阵
·保证输入板只有一个解决方案。
3.算法核心思想
本道题的思想和n皇后是比较相似,可以类比的是n皇后是在每一行,每一列,和两个斜 对角线上是有冲突的,数独是在每一列,每一行以及每个33的小方格当中是冲突的,而且在做算法的过程中都可以通过行优先的方式进行回溯,但是两个也有不同的地方,其中一点就 是n皇后在每一行只放置一个,但是数独是每一个位置都放置1-9的不同的数字。 在本道题当中,我使用的是通过行优先的方式,从一个矩阵的[0][0]位置开始,首先判断 在给出的数组当中这个位置是否是空格(即没有数字),如果没有数字,那么就从1-9逐一放 置数字,比如当我放置了一个1,于此同时,我要判断我放置的这个1是否能够满足我的每一 行每一列以及每个33的小方格上是否满足没有1,如果有1,那么就重新找2,如果2满足情 况,那么就是在这个位置上填2的基础上,在这一行上填其他的数字,如果填着填着发现在2 的基础上填这一行上的数字始终有不对的地方,那么进行返回,一直返回到刚刚填2的那个位 置,重新在这个位置上尝试3,以此类推,继续这样执行,如果发现,在某一行都填不出数字, 那么这个数独返回false无解,如果我的一行可以成功的填入数字,那么就是进行递归到下一 行再次重复上述的操作,直到进行到我的每一行都填完数字为止,当然如果不满足情况,那 么就是这个数独无解
分享代码
#include<iostream>
#include<vector>
using namespace std;
class solvesudoku //建立一个专门解决此类问题的类
{
public:
bool Bactrack(vector<vector<char>>& board,int row,int col);//这是一个回溯函数
bool isValid(vector<vector<char>>& board, int row, int col,char ch);//判断这个数字在行,列以及每个小方格上是否重复
};
bool solvesudoku::Bactrack(vector<vector<char>>& board, int row, int col) {
if (col == 9)//列为9,换到下一行
return Bactrack(board, row + 1, 0);
if (row == 9)//行为9,说明已经结束,回溯成功,数独有解
return true;
//从第0行第0列开始进行回溯
for (int i = row; i < 9; i++)
{
for (int j = col; j < 9; j++)
{
if (board[i][j] != ' ')
//如果上面有数字,则跳到下一列
return Bactrack(board, i, j + 1);
for (char ch = '1'; ch <='9'; ch++) //在这个方格当中对数字都进行一次尝试
{
if (!isValid(board, i, j, ch))//每次填入一个数字就对这个数字进行判断
continue;
board[i][j] = ch;//如果判断成功,那么就填入这个数字
if (Bactrack(board, i, j + 1))//判断成功的同时对这个位置的下一列进行判断,看看在这个数的基础上,这一行是否都成立
return true;
board[i][j] = ' ';//如果不成立,回溯换数字
}
return false;//如果这一行都回溯不成功,那么这个数独是无解的,返回错误
}
}
return false;
}
bool solvesudoku::isValid(vector<vector<char>>& board, int row, int col, char ch) {
for (int i = 0 ; i < 9; i++)
{
if (board[row][i] == ch)//这一行上是否有相等的
return false;
if (board[i][col] == ch)//这一列上是否有相等的
return false;
if (board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == ch)//在分块的小方格上是否有相同的
return false;
}
return true;
}
int main() {
vector<vector<char>> vec;//设一个二维的数组
solvesudoku Solution;
vector<char>v;// 一维数组
char tem;//方便提取输入的字符
cout << "Input:" << endl;
for (int i = 0; i < 9; i++)
{
v.clear();//进行一行的清除
for (int j = 0; j < 9; j++)
{
while (1) {
tem = getchar();
if (tem >= '1' && tem <= '9' || tem == ' ')
break;
}
v.push_back(tem);//压入一维数组
}
vec.push_back(v);//把一维数组压入二维数组
}
cout << endl;
if (Solution.Bactrack(vec, 0, 0)) //带入函数当中,如果函数返回值为真,就输出这个结果
{
cout << "Output:" << endl;
cout << endl;
cout << "[";
for (int i = 0; i < 9; i++) {
cout << "[";
for (int j = 0; j < 9; j++)
{
if(j!=8)
cout << "\"" << vec[i][j] << "\",";
else
cout << "\"" << vec[i][j] << "\" ";
}
cout << "],";
if(i!=8)
cout << endl;
}
cout << "]";
}
else //如果返回值假,就输出error表示这个数独无解
{
cout << "error";
}
system("pause");
}
运行结果