码迷,mamicode.com
首页 > 其他好文 > 详细

构造数独

时间:2015-09-13 21:43:47      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:构造数独   回溯的应用   深度搜索   数独如何生成   

编程之美有一道关于深度搜索和回溯应用的题目——构造数独:
数独的棋盘是由九九八十一个小方格组成的。玩家在每个小格子中,分别天上1至9的任意一个数字,让整个棋盘每一行,每一列,以及每一个3*3的小矩阵中的数字都不重复。
作者给两种解法:
解法一:
下面的GenerateValidMatrix()函数用经典的深度优先搜索来生成一个可行解。从(0,0)开始,对没有处理过的格子,调用GetValidValueList(coCurrent)来获得当前格子可能的取值选择,并从中取一个为当前格子的取值,接着搜索下一个格子。在搜索uocheng中,若出现某个格子没有可行的值,则回溯,修改前一个格子的取值,直到所有的格子都找到可行的取值为止,这是可行解。
本人下面的代码实现参考了http://blog.csdn.net/linyunzju/article/details/7673959博客,但我发现该博主的代码实现有一处代码顺序的执行错误,那就运行其构造数独的结果来看,发现最后一个格子竟然被赋值为0,还有就是他的代码实现只能固定的构造一个数独,一般是前面的格子从小到大赋值,而不是随机的去构造数独,这样不太符合构造不同的数独,本人对此代码做纠正和改进,有不恰之处,请多多包涵。
代码实现:

#ifndef COOR_H
#define COOR_H
//存储格子的行和列坐标
class Coor
{
   public:
      Coor(int xvalue=0,int yvalue=0)
      {
         x=xvalue;
         y=yvalue;
      }
      int x;
      int y;
};
#endif

#ifndef CELL_H
#define CELL_H
#include<stdlib.h>
//代表每个格子的详细信息
class Cell
{
   public:
      bool validList[10];//存储格子赋值情况信息
      int validValue;//格子赋值
      Cell()
      {
         memset(validList,true,10*sizeof(validList[0]));
         validValue=0;
      }
      //判断是否还存在有效值
      bool isNoValidValue()
      {
         for(int i=1;i<=10;i++)
         {
            if(validList[i]==true) return false;
         }
         return true;
      }
};
#endif // CELL_H

#include <iostream>
#include <cstdlib>
#include<Coor.h>
#include<Cell.h>
#define CLEAR(a) memset((a), 0, sizeof(a))
#define SIZE 9
Cell cell[SIZE+1][SIZE+1];//存储每个格子详细信息,索引代表格子的行和列坐标
int value[SIZE+1];//索引代表对应格子的赋值,而该数组值代索引的数字值对当前格子的有效性
using namespace std;
int pickNextVailVale(int x,int y)
{
   CLEAR(value);
   //遍历该已填的数字
   for(int i=1;i<y;i++)
   {
      value[cell[x][i].validValue]=1;
   }
   //遍历该列已填的数字
   for(int i=1;i<x;i++)
   {
      value[cell[i][y].validValue]=1;
   }
   //求出是属于哪一个九空格的第一个格子的行和列坐标
   int ninegrid_x=(x-1)/3*3+1;
   int ninegrid_y=(y-1)/3*3+1;
   // 遍历该九空格已填的数字
   for(int i=ninegrid_x;i<ninegrid_x+3;i++)
      for(int j=ninegrid_y;j<ninegrid_y+3;j++)
   {
      value[cell[i][j].validValue]=1;
   }
   //随机生成数字
   int randomValue=(int)rand()%9+1;
   while(true)
   {
      //存储已被用过的数字
      cell[x][y].validList[randomValue]=false;
      //如果该数字没被用过,则返回该数字
      if(value[randomValue]==0)
      {
         return randomValue;
      }
      //如果所有数字都被用过,则回溯前一个格子
      if(cell[x][y].isNoValidValue())
      {
         return -1;
      }
      //寻找下一个数字
      randomValue++;
      randomValue=randomValue%9+1;
   }
}
//寻找下一个格子
void next(Coor &curCoor)
{
   curCoor.y++;
   if(curCoor.y>9)
   {
      curCoor.y=1;
      curCoor.x++;
   }
}
//回溯前一个格子
void pre(Coor &curCoor)
{
   curCoor.y--;
   if(curCoor.y<1)
   {
      curCoor.y=9;
      curCoor.x--;
   }
}
int main()
{
   Coor coCurrent(1,1);
   while(true)
   {
      //找不到满足的情况
      if(coCurrent.x==0&&coCurrent.y==0)
         break;
      //附一个有效的数字
      cell[coCurrent.x][coCurrent.y].validValue=pickNextVailVale(coCurrent.x,coCurrent.y);
      //当当前格子没有找到满足的数字时,回溯前一个格子
      if(cell[coCurrent.x][coCurrent.y].validValue==-1)
      {
         //恢复初始化状态
         cell[coCurrent.x][coCurrent.y].validValue=0;
         memset(cell[coCurrent.x][coCurrent.y].validList,true,10*sizeof(cell[coCurrent.x][coCurrent.y].validList[0]));
         pre(coCurrent);
      }
       else
        {
         // 满足成功结果
            if (coCurrent.y==SIZE && coCurrent.x==SIZE)
            {
                for (int i=1; i<=SIZE; i++)
                {
                    for (int j=1; j<=SIZE; j++)
                        cout << cell[i][j].validValue << " ";
                    cout << endl;
                }
                break;
            }
            // 进一步搜索
            next(coCurrent);
        }
   }
    return 0;
}

解法二:
假设把整个棋盘分成9个九空格,按顺序分别命名为B1,B2,B3….B9.先从位于中心的九宫格随机用1到9填满该九宫格后,通过置换行的办法把B4和B6矩阵填好,然后对中央小矩阵的每一列做同样的变换,把B2和B8都解决了,再分别用B4和B6通过同样的一些系列矩阵变换生成B1和B7以及B2和B8,代码实现可以参考http://www.cnblogs.com/xulu/archive/2012/05/09/2491346.html

版权声明:本文为博主原创文章,未经博主允许不得转载。

构造数独

标签:构造数独   回溯的应用   深度搜索   数独如何生成   

原文地址:http://blog.csdn.net/xuguoli_beyondboy/article/details/48382145

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!