数独顾名思义——每个数字只能出现一次。数独是一种源自18世纪末的瑞士,后在美国发展、并在日本得以发扬光大的数字谜题。数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次。 这种游戏全面考验做题者观察能力和推理能力,虽然玩法简单,但数字排列方式却千变万化,所以不少教育者认为数独是训练头脑的绝佳方式。

关于数独的算法有很多种,最基本的有基拙挖掘法,唯一解法,侯选数置换法.查了很多资料但都没有找到完整的算法实现.花了30块银子到当当网上买了<<编程之美>>找到其中的章节,看完之后大失所望.其中的算法实现藏头露尾,寥寥几行.让人看的云里雾里.连类定义都没有给全.

这里只好自己用基拙挖掘法实现了一个完整的算法,现共享之.其核心思想是循环在每个单元格尝试如果能找到合适的数则前进.如果找不到则进行回朔.下面是代码实现.

如有bug 请一定告之,呵呵.mail:bingbing200x@163.com

* 算法思想:
     * 1.[数独的规则]是在每一行,每一列,以及每一个3*3的九宫格内都不能出现重复的数字,备选数字从1-9.
     * 关于数独的具体规则请看这一篇文章:http://blog.csdn.net/kabini/archive/2008/06/30/2598524.aspx
     * 2.为了数独的规则,则设置三个二维数组元素来记录行,列以及当前索引(x,y)所在的3*3九宫格内出现过的数字
     * 例如:rowExistArr[0,2]==1则表示在第0行,2这个数字已经出现,所以第0行不能再出现2这个数字
     *        colExistArr[0,2]==1 则表示在第0列,2这个数字已经出现,所以第0列不能再出现2这个数字
     *        mtxExistArr[0,2]==1,则表示在索引为0的3*3九宫格内,2这个数字已经出现,3*3九宫格图解请
     *        看GetMtxIndex方法上的注释.
     *  3.进行数独运算前会有一些预先初始的数字,  这些数字是不能改变的,  IsInitValue==true.每一个单元格对象
     *  SingleNumberCell ,都会有CellNumChoices对象这里记录这个当元格可供选择的数字列表。如果一个备选数字
     *  违反了数独的规则,则在备选列表中选择下一个数字。如果全都违反数独规则,则把当前对象销毁掉回朔到上一个
     *  单元格把上一个单元格的数字抹去重新从备选对象中选择下一个数字。IsProcessed==true的cell对象都是回退时
     *  经过的对象。

public class SingleNumberMatrix { #region 内部类 private class CellNumChoices { private Queue<int> _choices; public CellNumChoices(Queue<int> choices) { _choices = choices; } public int GetOneNum() { if (_choices.Count > 0) return _choices.Dequeue(); return SingleNumberMatrix.EMPTY; } } /// <summary> /// 数独矩阵中的单元格 /// </summary> private class SingleNumberCell { private int _xPos; private int _yPos; private int _value; private bool _bIsProcessed; private bool _bIsInitValue; private CellNumChoices _cellChoices; public SingleNumberCell(int x, int y, Queue<int> choices) { _xPos = x; _yPos = y; _bIsProcessed = false; _bIsInitValue = false; _cellChoices = new CellNumChoices(choices); } /// <summary> /// 从后选数组中找到一个可用的数,如果返回0,则需要进行回朔 /// </summary> /// <returns></returns> public bool GetOneChoice() { _value = _cellChoices.GetOneNum(); return _value > SingleNumberMatrix.EMPTY; } public int X { get { return _xPos; } set { _xPos = value; } } /// <summary> /// 当前元素是否已处理过 /// </summary> public bool IsProcessed { get { return _bIsProcessed; } set { _bIsProcessed = value; } } /// <summary> /// 是否是初始化时已存在的 /// </summary> public bool IsInitValue { get { return _bIsInitValue; } set { _bIsInitValue = value; } } public int V { get { return _value; } set { _value = value; } } public int Y { get { return _yPos; } set { _yPos = value; } } } #endregion private const int xCount = 9, yCount = 9; public const int EMPTY = 0; /// <summary> /// 备选数字 /// </summary> private int[] numChoices = new int[9] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; /// <summary> /// x轴行出现的数字 /// </summary> private int[,] rowExistArr = new int[xCount, yCount + 1]; /// <summary> /// y轴列出现的数字 /// </summary> private int[,] colExistArr = new int[xCount, yCount + 1]; /// <summary> /// 3*3一组的九个单元格内出现的数字 /// </summary> private int[,] mtxExistArr = new int[xCount, yCount + 1]; /// <summary> /// 数据矩阵 /// </summary> private int[,] _matrix; SingleNumberCell[,] _cellsMatix; /// <summary> /// 索引项 /// </summary> private int xIndex, yIndex; public SingleNumberMatrix(int[,] matrix) { _matrix = matrix; _cellsMatix = new SingleNumberCell[xCount, yCount]; } // 1 2 3 | 4 5 6 | 7 8 9 ->y // 4 5 6 | 7 8 9 | 1 2 3 // 7 8 9 | 1 2 3 | 4 5 6 // -------------------- // 2 3 4 | 5 6 7 | 8 9 1 // 5 6 7 | 8 9 1 | 2 3 4 // 8 9 1 | 2 3 4 | 5 6 7 // -------------------- // 3 4 5 | 6 7 8 | 9 1 2 // 6 7 8 | 9 1 2 | 3 4 5 // 9 1 2 | 3 4 5 | 6 7 8 public bool Run() { if (ValidMatrix(_matrix)) { for (xIndex = 0; xIndex < xCount; xIndex++) { for (yIndex = 0; yIndex < yCount; yIndex++) { if (null == this._cellsMatix[xIndex, yIndex]) { SingleNumberCell cell = new SingleNumberCell(xIndex, yIndex, GetCurChoices()); if (cell.GetOneChoice()) { this.SaveMtxState(cell.V); _cellsMatix[xIndex, yIndex] = cell; cell.IsProcessed = true; } else BackIndex(); } else { SingleNumberCell cell = _cellsMatix[xIndex, yIndex]; if (cell.IsInitValue) { if (cell.IsProcessed) BackIndex(); else cell.IsProcessed = true; continue; } this.ClearMtxState(cell.V); if (cell.GetOneChoice()) { this.SaveMtxState(cell.V); } else { _cellsMatix[xIndex, yIndex] = null; BackIndex(); } } }//end yIndex }//end xIndex Console.Write("Finished! congratulations to you ~!"); Console.WriteLine(); return true; } else { Console.Write("error:{rownum:" + xIndex.ToString() + "|colnum:" + yIndex.ToString() + "}"); return false; } } /// <summary> /// 回朔 /// </summary> private void BackIndex() { if (yIndex == 0) { if (xIndex > 0) { xIndex--; yIndex = yCount - 2; } } else yIndex -= 2; } public void Print() { Console.Write(" 0 1 2 3 4 5 6 7 8"); Console.WriteLine(); Console.Write("______________________________"); Console.WriteLine(); for (xIndex = 0; xIndex < xCount; xIndex++) { string str = string.Empty; for (yIndex = 0; yIndex < yCount; yIndex++) { if (yIndex == 0) str += xIndex.ToString() + " | "; str += this._cellsMatix[xIndex, yIndex].V.ToString(); str += " "; } Console.WriteLine(str); } } //[0,0] [0,1][0,2][0,3] [0,4][0,5][0,6] [0,7][0,8] ->y //[1,0] [1,1][1,2][1,3] [1,4][1,5][1,6] [1,7][1,8] //[2,0] [2,1][2,2][2,3] [2,4][2,5][2,6] [2,7][2,8] //[3,0] [3,1][3,2][3,3] [3,4][3,5][3,6] [3,7][3,8] //[4,0] [4,1][4,2][4,3] [4,4][4,5][4,6] [4,7][4,8] //[5,0] [5,1][5,2][5,3] [5,4][5,5][5,6] [5,7][5,8] //[6,0] [6,1][6,2][6,3] [6,4][6,5][6,6] [6,7][6,8] //[7,0] [7,1][7,2][7,3] [7,4][7,5][7,6] [7,7][7,8] //x //[8,0] [8,1][8,2][8,3] [8,4][8,5][8,6] [8,7][8,8] public static void Test() { int xCount = 9, yCount = 9; int[,] matrix = new int[xCount, yCount]; matrix[0, 0] = 8; matrix[2, 8] = 8; matrix[3, 3] = 8; matrix[4, 2] = 8; matrix[8, 4] = 8; SingleNumberMatrix si = new SingleNumberMatrix(matrix); try { if (si.Run()) si.Print(); } catch (Exception e) { Console.Write(e.Message); } } /// <summary> /// 根据当前索引,从备选数组中选一所有合法的数 /// </summary> /// <returns></returns> private Queue<int> GetCurChoices() { Queue<int> que = new Queue<int>(); foreach (int temp in numChoices) { if (ValidNum(temp)) { que.Enqueue(temp); } } return que; } /// <summary> /// 检测当前数,在行,列以及九宫格为单位的区域的合法性 /// </summary> /// <param name="temp"></param> /// <returns>true:代表当前数可用,false:代表当前数不可用</returns> private bool ValidNum(int temp) { if (rowExistArr[xIndex, temp] != EMPTY) return false; if (colExistArr[yIndex, temp] != EMPTY) return false; if (mtxExistArr[GetMtxIndex(), temp] != EMPTY) return false; return true; } /// <summary> /// 根据行,列获取当前x,y索引元素 /// 所在 3*3九宫格的索引 //0 0 0 | 0 0 0 | 0 0 0 //0 0 0 | 0 1 0 | 0 2 0 //0 0 0 | 0 0 0 | 0 0 0 // -------------------- //0 0 0 | 0 0 0 | 0 0 0 //0 3 0 | 0 4 0 | 0 5 0 //0 0 0 | 0 0 0 | 0 0 0 // -------------------- //0 0 0 | 0 0 0 | 0 0 0 //0 6 0 | 0 7 0 | 0 8 0 //0 0 0 | 0 0 0 | 0 0 0 /// </summary> /// <returns></returns> private int GetMtxIndex() { int xMatIndex = xIndex / 3; int yMatIndex = yIndex / 3; return xMatIndex * 3 + yMatIndex; } /// <summary> /// 记录矩阵的状态,行,列,以及九宫格的占用 /// </summary> private void SaveMtxState(int temp) { rowExistArr[xIndex, temp] = 1; colExistArr[yIndex, temp] = 1; mtxExistArr[GetMtxIndex(), temp] = 1; } private void ClearMtxState(int temp) { rowExistArr[xIndex, temp] = SingleNumberMatrix.EMPTY; colExistArr[yIndex, temp] = SingleNumberMatrix.EMPTY; mtxExistArr[GetMtxIndex(), temp] = SingleNumberMatrix.EMPTY; } /// <summary> /// 验证矩阵的合法性,并对行,列,以及九宫格出现的数字进行标记 /// </summary> /// <param name="matrix"></param> /// <returns></returns> private bool ValidMatrix(int[,] matrix) { for (xIndex = 0; xIndex < xCount; xIndex++) { for (yIndex = 0; yIndex < yCount; yIndex++) { int temp = matrix[xIndex, yIndex]; if (temp == EMPTY) continue; if (!ValidNum(temp)) return false; else { SingleNumberCell cell = new SingleNumberCell(xIndex, yIndex, null); cell.V = temp; cell.IsInitValue = true; this._cellsMatix[xIndex, yIndex] = cell; SaveMtxState(temp); } } } return true; } }

关于数独--九宫格的算法实现相关推荐

  1. 【算法分析】回溯法解数独(九宫格)算法

    这篇文章,是来详细介绍怎样写出一个算法,来解出所有的数独问题.算法的程序运行时间,缩减在了毫秒级别.等到这篇文章结束,我会抽时间写一篇文章,介绍如何生成一个随机的唯一解的数独问题.另外,为了做图形方便 ...

  2. 九宫怎么排列和使用_开心数独:好友都在玩的数独九宫格小游戏,居家无聊杀时间必备!...

    今日游戏推荐 开心数独 关键词:休闲益智.数独.2048.烧脑.数字推理.脑力游戏 游戏简介:数独九宫格,趣味数字谜题小游戏 游戏特色 <开心数独>游戏提供了关卡.随机.四宫.九宫多种玩法 ...

  3. Java——打印九宫格的算法思路(任意维奇数行方阵)

    九宫格算法口诀: 一居下行正中央,依次斜填切莫忘:下出框时向上放,右出框时向左放:排重便在上格填,右下排重一个样. 3 X 3 九宫格的算法思路: 1.始终将数字1放置在最后一行的中间位置: 2.数字 ...

  4. 一个简单数独求解的算法

    突发奇想,想解决一个数独的求解算法 直接贴代码吧! #include <stdio.h> #include <sqlite3.h> #include <string.h& ...

  5. 徐松亮算法教学-基于C语言的数独(九宫格)求解(含多解和解数统计)

    版权声明:本文为博主徐松亮的原创作品,未经允许不得转载,多谢支持!QQ:5387603 推荐点击此链接:欢迎进入徐松亮博客一站式导航搜索(随时更新) 目录 一,前言 二,开发环境 电脑系统 编译器 编 ...

  6. 数独的生成算法和解题算法

    github项目地址:https://github.com/Xcodingman/sudo.git 配置环境:windows10 vs2013 打开工程文件,运行相对应的cpp文件即可 1.数独解题与 ...

  7. java回溯算法解决数独_js回溯算法解决数独问题

    直接上代码 代码里面注释很清晰 传说中的最难数组大概是在20ms左右解决 /** * 数独算法 */ class Sudoku { constructor({ display = false, sud ...

  8. 数独 九宫格 小学奥数

    在处理到小学 如下 数独问题时 Input1: 0 2 0 8 0 7 3 0 0 9 0 0 1 0 0 5 7 0 8 3 0 0 0 5 2 0 0 0 4 0 0 8 0 6 0 0 0 0 ...

  9. java 数独算法_java版数独游戏核心算法(一)

    之前学习javascript时用javascript写过一个数独游戏,最近看了一点java的内容,于是就心血来潮想搞一个java版的数独游戏. 现在将全部代码分享出来和大家学习交流,当然代码中有着各种 ...

  10. 一个数独问题的算法(已更新,提供一个简单算法,欢迎拍砖)

    前段时间出差在外闲得无事看到一个数独问题.有三题,脑子不好使,只做出前两题.想想不如用程序来实现. 我先把题放出来大家有兴趣研究一下. 8 5 7 1 1 9 2 6 2 5 6 9 2 4 5 8 ...

最新文章

  1. VI3的VLAN配置:VST、EST和VGT标记
  2. No module named ‘__main__.common‘; ‘__main__‘ is not a package
  3. 存在sql注入漏洞的php,TCCMS在app/controller/news.class.php存在sql注入漏洞
  4. 趣图:他居然在前端写业务逻辑!
  5. javascript 快速入门
  6. Js求时间差、并转换为字符串
  7. 增长黑客手册——03
  8. 基于RT-Thread的环境监测装置(含IO口模拟8080时序驱动TFT屏幕)
  9. opencv4 QR码检测和识别源码解析
  10. 第一次进入页面,访问服务器图片报404,刷新或者回退重新进入,就可以加载图片。
  11. java转换中文日期格式_java 转换日期格式的方法
  12. 解决vmware虚拟机安装ubuntu 无法连接wifi找不到wifi适配器问题
  13. Android国际化,简体和繁体切换
  14. java公路车组装教程_自行车DIY入门教程,图文展示自行车组装全过程。(原创图文,转载请注明出处)...
  15. 解决CSDN上传MD文件不能显示照片
  16. 【香蕉oi】燃烧的火焰(最短路、状压)
  17. 武汉校区南非“留学生”:来传智播客学习是“独特的机会”
  18. 人像分割技术解析与应用
  19. [从源码学设计]蚂蚁金服SOFARegistry之时间轮的使用
  20. 二进制树型搜索算法选择电子标签的迭代过程

热门文章

  1. mysql支付账单怎么设计_订单与支付设计
  2. php 合并多个pdf,快速查阅多个PDF文件,这2个PDF合并技巧要学会!
  3. 关于不登陆微信如何傻瓜式查看记录
  4. 读书笔记2014第6本:《The Hunger Games》
  5. BootStrap 图标修改
  6. Fite-C02-1班成员学习进度记录
  7. 三星发布全球首款太阳能笔记本
  8. 用HTML和CSS做箭头
  9. 搜索引擎代码资源[转]
  10. 隐藏的BUG探讨——从“Y2K”问题到“2038”年问题