编程之美:第一章 1.15构造数独

/*
构造数独:
数独的棋盘是由九九八十一个小方格组成的。玩家在每个小格子中,分别天上1至9的任意一个数字,让整个棋盘每一行,每一列,以及每一个3*3的小矩阵中的数字都不
重复。

使用一个二维数组来存储,每一个元素对应数独中的一个数。但考虑到每一个格子有若干属性,可以把每个格子抽象为一个对象,把整体看成9*9个格子对象
生成游戏初始局面:可以向生成一个完整合法的解,然后再随机地去掉一些数字。

解法1:
假设用下面的结构来存储数独游戏:
int _size = 9;
Cell[,] _cells;
下面的GenerateValidMatrix()函数用经典的深度优先搜索来生成一个可行解。从(0,0)开始,对没有处理过的格子,调用GetValidValueList(coCurrent)来获得当前
格子可能的取值选择,并从中取一个为当前格子的取值,接着搜索下一个格子。在搜索uocheng中,若出现某个格子没有可行的值,则回溯,修改前一个格子的取值。
直到所有的格子都找到可行的取值为止,这是可行解。

没有完成
*/

#include <stdio.h>
#include <string.h>
const int LEN = 9;
int grid[LEN+1][LEN+1];
int visit[LEN+1][LEN+1];
int value[LEN+1];
int go[][2] = 
{
 {0,-1},//上
 {1,0},//右
 {0,1},//下
 {-1,0}//左
};

bool checkSmallMatrix(int iRow,int iCol)//检查每个小矩阵中是否存在1~9,9个数
{
 int iMark[LEN+1];
 memset(iMark,0,sizeof(iMark));
 for(int i = iRow ; i < iRow + 3 ; iRow++)
 {
  for(int j = iCol ; j < iCol + 3 ; iCol++)
  {
   iMark[ grid[i][j] ]++;
  }
 }
 for(int k = 1 ; k <= LEN ; k++)
 {
  if(iMark[k] != 1)
  {
   return false;
  }
 }
 return true;
}

bool check()
{
 bool isValid = true;
 int iMark[LEN+1];
 for(int i = 1 ; i <= LEN ; i++)//大数读每一行的检查
 {
  memset(iMark,0,sizeof(iMark));
  for(int j =  1; j <= LEN ; j++)
  {
   iMark[ grid[i][j] ]++;//正确的情况是每个数字出现的次数为1
  }
  for(int k = 1 ; k <= LEN ; k++)
  {
   if(iMark[k] != 1)
   {
    return false;
   }
  }
 }
 for(int j = 1 ; j <= LEN ; j++)//大数读每一列的检查
 {
  memset(iMark,0,sizeof(iMark));
  for(int i =  1; i <= LEN ; i++)
  {
   iMark[ grid[i][j] ]++;//正确的情况是每个数字出现的次数为1
  }
  for(int k = 1 ; k <= LEN ; k++)
  {
   if(iMark[k] != 1)
   {
    return false;
   }
  }
 }
 for(int i = 1 ; i <= LEN ; i += 3)//小数独每个的检查
 {
  for(int j = 1; j <= LEN ; j += 3)
  {
   if(checkSmallMatrix(i,j) == false)
   {
    return false;
   }
  }
 }
 return true;
}

void dfs(int x,int y,int pos)//深度优先搜索,首先要设定开始和结束值,剪枝标记,终点是9,9
{
 if(x == LEN && y == LEN && check())//如果已经抵达终点,并且符合是数独的条件,那么,输出该数独后结束
 {
  for(int i = 1 ; i <= LEN ; i++)
  {
   for(int j = 1 ; j <= LEN ; j++)
   {
    if(j != 1)
    {
     printf(" %d",grid[i][j]);
    }
    else
    {
     printf("%d",grid[i][j]);
    }
   }
   printf("\n");
  }
 }
 else//递归主体
 {
  for(int i = 0 ; i < 4 ; i++)
  {
   int iNewX = x + go[i][0];
   int iNewY = y + go[i][1];
   if(!visit[iNewX][iNewY] && x >= 1 && x <= LEN && y >= 1 && y <= LEN)//没有访问过,没有越界,就继续向下访问。
    //还需要尝试给grid[x][y]进行赋值 ,赋值的元素范围在!~9之间
   {
    for(int k = pos + 1 ; k <= LEN ; k++)
    {
     visit[iNewX][iNewY] = 1;
     grid[iNewX][iNewY] = k;
     dfs(iNewX,iNewY,pos+1);
     visit[iNewX][iNewY] = 0;//回溯
     grid[iNewX][iNewY] = 0;
    }
   }
  }
 }
}

void next(int& x,int& y)
{
 x++;
 if(x > 9)
 {
  x = 1;
  y++;
 }
}

void pre(int& x,int& y)
{
 x--;
 if(x < 1)
 {
  x = 9;
  y--;
 }
}

int pickNextValidValue(int x,int y,int cur)
{
 memset(value,0,sizeof(value));
 int i,j;
 for(i = 1 ; i < y ;i++)
 {
  value[ grid[i][x] ] = 1;//?
 }
 for(j = 1 ; j < x ; j++)
 {
  value[ grid[y][j] ] = 1;//?
 }
 int u = (x-1)/3*3 + 1;//?
 int v = (y-1)/3*3 + 1;
 for(i = v; i < v + 3 ; i++)
 {
  for(j = u ; j < u + 3 ; j++)
  {
   value[ grid[i][j] ] = 1;//?
  }
 }
 for(i = cur + 1; i <= LEN && value[i] ; i++);
 return i;
}

int times = 0;

void process2()
{
 int x,y,i,j;
 x = y = 1;
 //深度优先搜索
 while(true)
 {
  times++;
  if(x == LEN && y == LEN)//满足成功结果
  {
   for(i = 1; i <= LEN ; i++)
   {
    for(j = 1 ; j <= LEN ; j++)
    {
     printf("%d ",grid[i][j]);
    }
    printf("\n%d",times);
    break;
   }
  }
  if(y == 0)//满足失败结果
  {
   break;
  }
  grid[y][x] = pickNextValidValue(x,y,grid[y][x]);//改变状态
  if(grid[y][x] > LEN)//恢复状态
  {
   grid[y][x] = 0;
   pre(x,y);
  }
  else
  {
   next(x,y);
  }
  for(i = 1 ; i <= LEN ; i++)
  {
   for(j = 1 ; j <= LEN ; j++)
   {
    printf("%d ",grid[i][j]);
   }
   printf("\n");
  }
 }
}

void process()
{
 memset(visit,0,sizeof(visit));
 visit[1][1] = 1;
 dfs(1,1,1);
}

int main(int argc,char* argv[])
{
 process2();
 getchar();
 return 0;
}

//typedef struct Coordinate
//{
// int _iX;
// int _iY;
//}Coordinate;


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值