数独(九宫格)的高效算法

      比较容易想到的是用回溯法,从第一个格子开始到最后一格,每个格子由1到9进行尝试,看能否填下去,不能就回头。思路简单,可是执行时间太长了。有没有更加高效的搜索算法了?当然有。
      我们仅需要改变搜索的顺序,或者说改变填数的方法。
     先将数字1分别填入1到9区域中,然后再将数字2填入1到9区域,重复该操作,直到所有空位都被填满为止。
     为什么这样就快了?因为先将一个数字成功填入9个区域的制约性,远远大于按顺序地从第一个填到最后一个格。假设第一行全是空的,在第一行的第一格填了数字1,然后假如在第二行填不下数字1,证明第一行的数字1填错了,这时通过回溯纠正它,最坏需要9!次。
但如果是一个个区域地填入数字1,当第二个1填不下时,马上就能回溯到上一个1去纠正它的位置了。
具体C语言源程序如下:
#include<stdio.h>
#include<string.h>
int quyu[4][4]={{0,0,0,0},
                        {0,1,2,3},
                        {0,4,5,6},
                        {0,7,8,9}};
int a[10][10],hang[10][10],lie[10][10],grid[10][10],sum;
int p[10][2]={{0,0},{1,1},{1,4},{1,7},{4,1},{4,4},{4,7},{7,1},{7,4},{7,7}};
//p[i][0]和p[i][1]数组记录第i个区域的左上角的横纵坐标
void init()
{
 int i,j,k;
 memset(hang,0,sizeof(hang));
 memset(lie,0,sizeof(lie));
 memset(grid,0,sizeof(grid));
 sum=0; 
 for(i=1;i<=9;i++)

 for(j=1;j<=9;j++) 

 {

   scanf(“%d”,&k);

   a[i][j]=k;

   if(k)

  {

    hang[i][k]=1;    //第i行填入k了
    lie[j][k]=1;       //第j列填入k了
    grid[quyu[(i-1)/3+1][(j-1)/3+1]][k]=1;  //  (i , j)所在区域填入k了


    sum++;

   }

 }
}
void outt()
{
 int i,j;
 for(i=1;i<=9;i++)
 {
  for(j=1;j<=8;j++) printf(“%d “,a[i][j]);
  printf(“%d\n”,a[i][9]);
 }
}

void solve(int k1,int k2)  //将数字k1填入区域k2
{
  int x,y,i,j;
  if(sum==81) {outt();return;}  //数独全填好了就输出
  if(grid[k2][k1])   //区域k2中已有数字k1了
  {
   if(k2<9) solve(k1,k2+1); //填下一个区域
   else solve(k1+1,1); //填下一个数字
  }

  x=p[k2][0]; y=p[k2][1];

  for(i=x;i<=x+2;i++)

for(j=y;j<=y+2;j++)

if(a[i][j]==0 && hang[i][k1]==0 && lie[j][k1]==0) //第(i,j)格为空,且可填入k1

{

a[i][j]=k1;

sum++;

hang[i][k1] = lie[j][k1] = 1;


if(k2<9) solve(k1,k2+1); //填下一个区域

else solve(k1+1,1); //填下一个数字


a[i][j]=0;

sum–;


hang[i][k1] = lie[j][k1] = 0;

}
}

int main()
{
 init();
 solve(1,1);  //将数字1从区域1开始填起
 return 0;
}

    原文作者:九宫图算法
    原文地址: https://blog.csdn.net/li_wei_quan/article/details/50359699
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞