用代码证明自己闲的蛋疼(三)——回溯法做数独

数独大家应该都玩过,1~9数字,满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。

起始会有一些给定的值,然后我们去填剩余的数,一个合理的数独最终解一定是唯一的。

九日哥也很喜欢玩数独,喜欢到最后都懒得算了,直接写个程序搜出答案。。。



解决思路是回溯,如果对回溯不了解的同学可以移步 http://blog.csdn.net/sm9sun/article/details/53244484

其实想一想,数独的规则是不是跟N皇后很相似??


我们假设一个9X9的二维数组a[9][9],如何判断值k是否可以插入某个点a[i][j]呢?

①该数组所有横向没有存在过k值

for(n=0;n<9;n++)
 if(a[i][n]==k)return 0;

②该数组纵向没有存在过k值

for(m=0;m<9;m++)
 if(a[m][j]==k)return 0;

③该点位于的九宫格3X3区间没有存在过k值

xm=(i/3)*3,xn=(j/3)*3; 
 for(m=xm;m<xm+3;m++)
 for(n=xn;n<xn+3;n++)
 if(a[m][n]==k)return 0;


再来看看搜索的过程,9X9总共81个格子,我们以一个数字n作为标记i,j坐标点的变量(i=n/9; j=n%9;)

即:80就相当于最后一个格子  8/9=8,8%9=8(数组以0开始)


如果n等于80,那么就表示我已经遍历到最后一个点了,如果满足条件的话我们就找到最终解了。

如果n不等于80,表示我们还要继续往下试,即用不同的k值试探当前i,j点是否可以放下

回归后回溯即可~

void SD(int a[9][9],int n)//求解
{
 int i,j;
 int b[9][9];
 for(i=0;i<9;i++)
 for(j=0;j<9;j++)
 b[i][j]=a[i][j];        //用b进行尝试
 i=n/9; j=n%9;              //行列 
 if(a[i][j]!=0)             //如果该位置固定 
 (n==80)?print(b):SD(b,n+1);
 else
 { 
  int k;                       //试数 
  for(k=1;k<=9;k++)
  if(test(b,i,j,k)) //可以 
   {
    b[i][j]=k;
    n==80?print(b):SD(b,n+1);
    b[i][j]=0; //回溯 
   }
 }
}

完整代码如下:

#include<stdio.h>
int count=0; 
void print(int a[9][9])
{
 count++;
 printf("case: %d:\n",count);
 for(int i=0;i<9;i++)
 for(int j=0;j<9;j++)
  {
   printf("%d",a[i][j]);   
   j==2?printf(" "):0;
   j==5?printf(" "):0;
   j==8?printf("\n"):0;
   j==8&&i%3==2?printf("\n"):0; 
  }
}
//判断是否可以将第i行、第j列的数设为k
int test(int a[9][9],int i,int j,int k)
{
 int m,n,xm,xn;
 
 for(n=0;n<9;n++)
 if(a[i][n]==k)return 0;
 
 for(m=0;m<9;m++)
 if(a[m][j]==k)return 0;
 
 xm=(i/3)*3,xn=(j/3)*3; 
 for(m=xm;m<xm+3;m++)
 for(n=xn;n<xn+3;n++)
 if(a[m][n]==k)return 0;

 return 1;
}

void SD(int a[9][9],int n)//求解
{
 int i,j;
 int b[9][9];
 for(i=0;i<9;i++)
 for(j=0;j<9;j++)
 b[i][j]=a[i][j];        //用b进行尝试
 i=n/9; j=n%9;              //行列 
 if(a[i][j]!=0)             //如果该位置固定 
 (n==80)?print(b):SD(b,n+1);
 else
 { 
  int k;                       //试数 
  for(k=1;k<=9;k++)
  if(test(b,i,j,k)) //可以 
   {
    b[i][j]=k;
    n==80?print(b):SD(b,n+1);
    b[i][j]=0; //回溯 
   }
 }
}
int main()
{
 int a[9][9];
 printf("请输入原始数据,没有数据用0代替。\n");
 for(int i=0;i<9;i++)
 for(int j=0;j<9;j++)
 scanf("%d",&a[i][j]);
 printf("-------------------\n\n");
 SD(a,0);
 if(count==0)
 printf("此数独无解!");
 return 0;
}








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值