求解数独的C++实现

求解数独的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 >= 
  • 7
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值