求解数独的C++实现
动机
在做数独的时候,抱着好奇心想做一个数独求解的程序。
当时我并没有接触多少算法,也是抱着试试看的心态编写了这个数独求解器。
解数独的方法
要写一个求解数独的程序,必须要线弄清楚要用什么方法去求解数独。一般是采取简单的摒除法,然而事实上摒除法并不能做比较高级的数独。深究下去发现较高级的数独可用的方法多达十种,而且面对不同的数独要运用不同的方法,相应的算法打码量十分庞大,而且并没有一个一定的套路。计算机擅长重复单调工作,为了程序能更好的设计,我考虑使用候选数法,在候选数法不能得到解的时候采取搜索的方法,这样能保证一定的性能下一定能求出一个数独的解。
设计思路
主要流程
这里主要涉及两个功能,一个是摒除法,一个是搜索。
那么这里是先使用摒除法,如果摒除法不可继续求解的时候使用搜索,搜索之后使用摒除法探求正确性,一旦有错回溯并搜索下一个可能解。
这是程序的大致框架:
(自豪地使用processon)
主要功能
采用分离实现和接口的方式。
//sudoku.h
class sudoku
{
public:
sudoku();//读取文件,初始化数独
void printsudo();//打印数独
int solve();//求解
void outputsudoku();//输出解文件
int checksudoku();//检查数独是否正确
private:
int search();//搜索求解
int checkclear();//返回未填写的格子数
void base_solve();//摒除求解
void clear_solv_sudoku(int, int, int);//删除不可能的候选数
void update_ques_sudoku();//填写唯一候选数到数独
int ques_sudoku[9][9];//数独
int solv_sudoku[9][9][9];//候选数
};
为了能更好的计算候选数,同时不给原来的数独带来麻烦,我设计两个数组:一个是用来记录数独的,一个是用来记录候选数的。
填充数独的时候先使用摒除法base_solve()
,首先删除不可能的候选数clear_solv_sudoku(int, int, int)
,然后填写唯一候选数到数独update_ques_sudoku()
。然后在不能继续摒除的时候使用搜索search()
。
总体程序框架如下:
(自豪地使用processon)
功能实现
接下来就是对应的编写相应代码
//sudoku.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
using std::ofstream;
using std::ios_base;
#include "sudoku.h"
//读取文件并初始化数组
sudoku::sudoku()
{
//读取文件到数组
ifstream infile;
infile.open("sudoku.txt");
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
infile >> ques_sudoku[i][j];
}
}
infile.close();
//初始化候选数
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (ques_sudoku[i][j] == 0)
{
for (int k = 0; k < 9; k++)
{
solv_sudoku[i][j][k] = 1;
}
}
else
{
for (int k = 0; k < 9; k++)
{
solv_sudoku[i][j][k] = 0;
}
}
}
}
}
//检查数独是否正确
//正确返回1,错误返回0
int sudoku::checksudoku()
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (ques_sudoku[i][j] < 0 || ques_sudoku[i][j] >9)
{
return 0; }
for (int k = 0; k < 9; k++)
{
for (int l = 0; l < 9; l++)
{
if (i == k && ques_sudoku[i][j] == ques_sudoku[k][l] && ques_sudoku[i][j] && j != l)
{
return 0; }
if (j == l && ques_sudoku[i][j] == ques_sudoku[k][l] && ques_sudoku[i][j] && i != k)
{
return 0; }
if (((i >=