问题来源:leetCode Sudoku Solver

Write a program to solve aSudoku puzzle by filling the empty cells. 
Empty cells are indicated by the character *.*. 
You may assume that there will be only one unique solution.

问题链接: 
https://oj.leetcode.com/problems/sudoku-solver/

功能:

自动解数独题

大概方案: 
采用以行为单位的DFS来寻找答案。

提纲: 
0、对全部数据进行候选数预处理,记录下每个空格的候选数。

1、根据候选数表和当前结果表,以行为单位,递归产生所有可能的行,并加入结果数组,然后对每一个产生的可能行进行新一轮的递归调用。这里有一个互相递归调用的行为。

2、若无法产生可能的行或产生完所有行的下一级返回假,则返回假。

3、若有一个下级递归返回真或者最后一行中成功产生了可能的行,返回真。

主要方法概览: 
(注意:候选数表为全局数组,所有方法可以直接访问)

0、bool tryRow(introw,vector<vector<int> > &res); 
该方法为对某行进行数字试填,row为某行的行号,res为当前结果数组。

1、bool fillRow(introw,int col,vector<int> &now,vector<vector<int> >&res); 
该方法为对特定的格子进行数字试填,row为行号,col为列号,now为当前行中已填的数字,res为结果数组。

2、以上两种方法互相递归调用。对于特定新行,调用tryRow方法,而填新行内的数则递归调用fillRow,当当前行已经填满后,在fillRow中调用新一轮的tryRow方法进入下一行。

Solution类的全部代码和注释:(\t被吞,用/*...*/来缩进)

#include <iostream> 
#include <vector> 
#include <cstdio> 
using namespace std;

class Solution 

public: 
/*......*/ int sel[9][9][10]; 
// 候选数数组,sel[x][y][0]标记横坐标为x,纵坐标为y的格子是否有数字,有则为该数字, 
// 待填则sel[x][y][num](1<= num <=9)为1表示该格子可选数包括num.

/*......*/ Solution() 
/*......*/ { 
/*.........*/ for (int i = 0;i < 9;i++) 
/*............*/ for (int j = 0;j <9;j++) 
/*...............*/ for (int p = 0;p <10;p++) 
/*..................*/ sel[i][j][p] = 1; 
/*......*/ } 
/*......*/ voidsolveSudoku(vector<vector<char> > &board) // 主处理方法 
/*......*/ { 
/*.........*/ vector<vector<int>> res; 
/*.........*/ init(board); // 进行候选数初始化处理 
/*.........*/ tryRow(0,res);

/*.........*/ int len1 = board.size(); 
/*.........*/ int len2 = board[0].size(); 
/*.........*/ for (int i = 0;i <len1;i++) 
/*............*/ for (int j = 0;j <len2;j++) 
/*...............*/ if (board[i][j] == *.*) 
/*..................*/ board[i][j] =res[i][j] + *0*; 
/*......*/ } 
/*......*/ bool tryRow(introw,vector<vector<int> > &res) 
/*......*/ { 
/*.........*/ if (row >= 9) 
/*.........*/ { 
/*............*/ return true; 
/*.........*/ } 
/*.........*/ bool flag = false; 
/*.........*/ vector<int> now(10); 
/*.........*/ flag =fillRow(row,0,now,res); 
/*.........*/ return flag; 
/*......*/ }

/*......*/ bool fillRow(int row,intcol,vector<int> &now,vector<vector<int> > &res) 
/*......*/ { 
/*.........*/ bool flag = false; 
/*.........*/ if (col >= 9) 
/*.........*/ { 
/*............*/ res.push_back(now); 
/*............*/ flag = tryRow(row +1,res); 
/*............*/ if (flag == false) 
/*...............*/ res.pop_back(); 
/*............*/ return flag; 
/*.........*/ } 
/*.........*/ if (sel[row][col][0] != 0) 
/*.........*/ { 
/*...............*/ now[col] =sel[row][col][0]; 
/*...............*/ flag = fillRow(row,col+ 1,now,res); 
/*...............*/ return flag; 
/*.........*/ } 
/*.........*/ int hash[10] = {0}; // now中现存的数为1,该数组中为1的数不能选 
/*.........*/ for (int i = col - 1;i >=0;i--) // 判断当前行中需要更新的候选数 
/*............*/ hash[now[i]] = 1; 
/*.........*/ update(row,col,hash,res); // 该函数继续更新该格子的候选数 
/*......*/ for (int i = 1;i <= 9;i++) 
/*.........*/ { 
/*............*/ if (hash[i] == 0&& sel[row][col][i] == 1) 
/*............*/ { 
/*...............*/ now[col] = i; 
/*...............*/ flag = fillRow(row,col+ 1,now,res); 
/*...............*/ if (flag) 
/*..................*/ return true; 
/*............*/ } 
/*.........*/ }/*...*/ 
/*.........*/ return flag; 
/*......*/ }/*...*/ 
/*......*/ 
/*......*/ void update(int row,int col,int*hash,vector<vector<int> > &res) 
/*......*/ { 
/*.........*/ int top = getTop(row); 
/*.........*/ int left = getLeft(col); 
/*.........*/ for (int i = row - 1;i >=0;i--) // 既有结果列中的数不能选 
/*.........*/ { 
/*...............*/ hash[res[i][col]] = 1; 
/*.........*/ } 
/*.........*/ if (row > top) 
/*.........*/ { 
/*............*/ int count = row - top; 
/*............*/ for (int i = 0;i <count;i++) 
/*...............*/ for (int j = 0;j <3;j++) 
/*..................*/hash[res[top+i][left+j]] = 1; 
/*.........*/ } 
/*......*/ }

/*......*/ voidinit(vector<vector<char> > &board) 
/*......*/ { 
/*.........*/ int len1 = board.size(); 
/*.........*/ int len2 = board[0].size(); 
/*.........*/ for (int i = 0;i <len1;i++) 
/*............*/ for (int j = 0;j <len2;j++) 
/*............*/ { 
/*...............*/ if (board[i][j] != *.*) 
/*...............*/ { 
/*..................*/ setRow(i,board[i][j]- *0*); 
/*..................*/ setCol(j,board[i][j]- *0*); 
/*..................*/setCel(i,j,board[i][j] - *0*); 
/*..................*/ sel[i][j][0] =board[i][j] - *0*;/*...*/ 
/*...............*/ } 
/*...............*/ else 
/*..................*/ sel[i][j][0] = 0; 
/*............*/ } 
/*......*/ } 
/*......*/ void setRow(int i,int num) 
/*......*/ { 
/*.........*/ for (int j = 0;j < 9;j++) 
/*.........*/ { 
/*............*/ sel[i][j][num] = 0; 
/*.........*/ } 
/*......*/ } 
/*......*/ void setCol(int j,int num) 
/*......*/ { 
/*.........*/ for (int i = 0;i < 9;i++) 
/*.........*/ { 
/*............*/ sel[i][j][num] = 0; 
/*.........*/ } 
/*......*/ } 
/*......*/ void setCel(int x,int y,intnum)// 求方格的左上坐标 
/*......*/ { 
/*.........*/ int top,left; 
/*.........*/ top = getTop(x); 
/*.........*/ left = getLeft(y); 
/*.........*/ for (int i = 0;i < 3;i++) 
/*............*/ for (int j = 0;j <3;j++) 
/*...............*/ sel[i+top][j+left][num]= 0; 
/*......*/

// 该函数同getTop一样,用来求位于x行y列的格子所在的正方形格的位置。 
/*......*/ int getLeft(int col)  
/*......*/ { 
/*.........*/ int tmp; 
/*.........*/ int left; 
/*.........*/ tmp = col % 9; 
/*.........*/ if (tmp >= 6) 
/*.........*/ { 
/*............*/ left = 6; 
/*.........*/ } 
/*.........*/ else if (tmp >= 3) 
/*............*/ left = 3; 
/*.........*/ else 
/*............*/ left = 0; 
/*.........*/ return left; 
/*......*/ }

/*......*/ int getTop(int row) 
/*......*/ { 
/*.........*/ int tmp; 
/*.........*/ int top; 
/*.........*/ tmp = row % 9; 
/*.........*/ if (tmp >= 6) 
/*.........*/ { 
/*............*/ top = 6; 
/*.........*/ } 
/*.........*/ else if (tmp >= 3) 
/*.........*/ { 
/*............*/ top = 3; 
/*.........*/ } 
/*.........*/ else 
/*............*/ top = 0; 
/*.........*/ return top; 
/*......*/ } 
};

// 测试函数 
int main(void) 

/*...*/ vector<char> now; 
/*...*/ vector<vector<char> >res; 
/*...*/ int c; 
/*...*/ Solution *p = new Solution(); 
/*...*/ while ((c = getchar()) != EOF) 
/*...*/ { 
/*......*/ if (c != '\n') 
/*.........*/ now.push_back(c); 
/*......*/ else 
/*......*/ { 
/*.........*/ res.push_back(now); 
/*.........*/ now.clear(); 
/*......*/ } 

/*...*/ p->solveSudoku(res); 
/*...*/ return 0; 
}

【原创】一个基于简单剪枝的DFS解数独程序的更多相关文章

  1. 用qpython3写一个最简单的发送短信的程序

    到目前为止并没有多少手机应用是用python开发的,不过qpython可以作为一个不错的玩具推荐给大家来玩. 写一个最简单的发送短信的程序,代码如下: #-*-coding:utf8;-*- #qpy ...

  2. HDU 1426 Sudoku Killer(dfs 解数独)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1426 Sudoku Killer Time Limit: 2000/1000 MS (Java/Oth ...

  3. [原创]python之简单计算器(超详解,只有基本功能+-*/,还有括号处理)

     不想看过程的话,直接看文章最后的正式源码 作业需求及分析: 流程图 https://www.processon.com/diagraming/580c5276e4b03c844a5a9716 初期感 ...

  4. 一个基于Socket的http请求监听程序实现

    首先来看以下我们的需求: 用java编写一个监听程序,监听指定的端口,通过浏览器如http://localhost:7777来访问时,可以把请求到的内容记录下来,记录可以存文件,sqlit,mysql ...

  5. 用scala实现一个基于TCP Socket的快速文件传输程序

    这是用scala实现的一个简单的文件传输程序. 服务端 package jpush import java.io.{DataInputStream, File, FileOutputStream} i ...

  6. 如何使用 Docker 部署一个基于 Play Framework 的 Scala Web 应用?

    本文作者 Jacek Laskowski 拥有近20年的应用程序开发经验,现 CodiLime 的软件开发团队 Leader,曾从 IBM 取得多种资格认证.在这篇博文中,Jacek 分享了 Wars ...

  7. 新项目架构从零开始(三)------基于简单ESB的服务架构

    这几个月一直在修改架构,所以迟迟没有更新博客. 新的架构是一个基于简单esb的服务架构,主要构成是esb服务注册,wcf服务,MVC项目构成. 首先,我门来看一看解决方案, 1.Common 在Com ...

  8. 使用python解数独

    偶然发现linux系统附带的一个数独游戏,打开玩了几把.无奈是个数独菜鸟,以前没玩过,根本就走不出几步就一团浆糊了. 于是就打算借助计算机的强大运算力来暴力解数独,还是很有乐趣的. 下面就记录一下我写 ...

  9. Kcptun 是一个非常简单和快速的,基于KCP 协议的UDP 隧道,它可以将TCP 流转换为KCP+UDP 流

    本博客曾经发布了通过 Finalspeed 加速 Shadowsocks 的教程,大家普遍反映能达到一个非常不错的速度.Finalspeed 虽好,就是内存占用稍高,不适合服务器内存本来就小的用户:而 ...

随机推荐

  1. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  2. android app 架构设计02

    二:在开放的过程中,尽量把工具类,BaseActivity 放在指定的位置. DateFormat Bitmap Notification Shared Preference Environment ...

  3. 图像处理特征不变算子系列之Moravec算子(一)

    论文转载请注明出处:http://blog.csdn.net/kezunhai 1977年,Moravec提出了兴趣点(Points of Interests)的概念,并应用于解决Stanford C ...

  4. jquery实现鼠标拖动

    <html>   <head>   <script type='text/javascript' src='js/jquery-1.5.1.js'></scr ...

  5. Opencv246+vs2012生成不依赖编译环境的exe文件

    我们都知道,vs2012编译项目有两个版本号:Debug和Release,这里我们在Release下生成exe文件,为什么要在Release以下生成呢,原因是你在Debug模式下生成的exe须要vs2 ...

  6. KMP算法的Next数组详解(转)

    转载请注明来源,并包含相关链接. 网上有很多讲解KMP算法的博客,我就不浪费时间再写一份了.直接推荐一个当初我入门时看的博客吧: http://www.cnblogs.com/yjiyjige/p/3 ...

  7. [ACM] poj 1258 Agri-Net (最小生成树)

    Agri-Net Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37131   Accepted: 14998 Descri ...

  8. 抽出SqlHelper

    什么叫SqlHelper,通过简单的翻译,能够获得这是对Sql的帮助,那么它究竟对我们的Sql做出了什么样的帮助呢? 在一款软件的设计编程中,总是会对数据库有连接的.假设你用的是SqlServer的数 ...

  9. 吐槽CSDN编辑

    Perface 近期喜欢上了markdown.我认为它就是一些HTML标签的快捷键,用一些符号来取代标签,易学易读易用,何乐而不为呢?近期也喜欢用印象笔记来让我的记忆永存,确实它强大的收集能力让我迷上 ...

  10. 读 Working with forms 一些心得

    Working with forms About this document This document provides an introduction to Django’s form handl ...