今天开博了2007-7-16

开博没有太监的客。。。

 

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

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

 

 

8

 

 

 

5

7

1

1

9

 

 

 

 

 

 

2

 

6

 

2

 

 

 

 

 

 

5

 

6

 

9

 

 

 

 

 

2

4

 

5

8

 

 

 

 

 

8

 

1

 

2

 

 

 

 

 

 

4

 

9

 

4

 

 

 

 

 

6

5

7

5

8

9

 

 

 

1

 


 

 

 

 

 

5

 

 

2

 

 

1

9

6

 

 

 

3

 

3

5

 

 

 

7

6

 

 

 

6

1

 

4

 

7

 

 

7

 

2

 

6

 

4

 

 

5

 

3

 

8

6

 

 

 

9

7

 

 

 

8

3

 

5

 

 

 

8

3

9

 

 

8

 

 

7

 

 

 

 

 


 

6

 

 

1

7

 

 

 

 

1

9

3

6

 

 

 

 

 

 

 

 

 

 

 

 

4

 

5

 

 

 

2

 

 

8

8

 

1

 

 

 

7

 

2

2

 

 

7

 

 

 

6

 

6

 

 

 

 

 

 

 

 

 

 

 

 

7

6

5

3

 

 

 

 

5

4

 

 

8

 


规则:
在9*9的格子中用1到9填满格子:
每一行都要用到1~9,位置不限;
每一列都要用到1~9,位置不限;
每3*3格子都要用到1~9,位置不限;

我的算法思想比较简单:穷举法,递归。
1、初始化:
 新建两个数组A[9,9],B[9,9],他们的初始值都一样。

         public  static int[,,] A = new int[9,9,9];

         public  static int[,] B = new int[9,9];

              for(int i=0;i<9;i++)

                   for(int j=0;j<9;j++)

                       A[i,j] = 0;

              A[0,1]=6;

              A[0,4]=1;

              A[0,5]=7;

                   ………………

              A[8,3]=5;

              A[8,4]=4;

              A[8,7]=8;

              A[8,8]=6;


              for(int m=0;m<9;m++)

                   for(int n=0;n<9;n++)

                       B[m,n] = 0;

              B[0,1]=6;

              B[0,4]=1;

              B[0,5]=7;

                   ………………

              B[8,3]=5;

              B[8,4]=4;

              B[8,7]=8;

              B[8,8]=6;

 

递归过程:

         public void JudgeNumber(int x,int y)

         {

              if(x<9&&y<9)                                 //判断数组下标范围

              {

                   if(A[x,y] == 0||A[x,y] != B[x,y])       //如果数组的值为零或者取得的值不等于B的值

                   {

                       for(int i=1;i<10;i++)               

                       {

                            A[x,y] = i;                     //循环付值

                            if(Pass(x,y))                   //判断条件

                            {

                                 if(Victory())              //成功

                                 {

                                     printShuzu();

                                     return ;

                                 }

                                 if(y<8)                     //判断下一个数

                                     JudgeNumber(x,y+1);

                                 else

                                     JudgeNumber(x+1,0);

                            }

                       }

                       A[x,y] = 0;                           //失败之后把值设为零,以便继续判断

                   }

                   else                                      //判断下一个数

                   {

                       if(y<8)

                            JudgeNumber(x,y+1);

                       else

                            JudgeNumber(x+1,0);

                   }

              }

         }

 

         public bool Pass(int i,int j)

         {

            //判断横竖有无重复

              for(int b=0;b<9;b++)

              {

                   if(b!=i)

                       if(A[i,j] == A[b,j])

                            return false;

                   if(b!=j)

                       if(A[i,j] == A[i,b])

                            return false;

              }

 

            //判断*3有无重复

              int q0 = (i/3)*3;

              int k0 = (j/3)*3;

              int q1 = (i/3+1)*3;

              int k1 = (j/3+1)*3;

 

              for(int q=q0;q<q1;q++)

                   for(int k=k0;k<k1;k++)

                       if(q!=i&&k!=j)

                            if(A[i,j] == A[q,k])

                                 return false;

              return true;

         }

 

        /// <summary>

        /// Pass情况下如果整个数组无0表示成功求解

        /// </summary>

        /// <returns></returns>

         public bool Victory()

         {

              bool ax=false;

             

              for(int i=0;i<9;i++)

                   for(int j=0;j<9;j++)

                   {

                       if(  A[i,j] != 0)

                            ax =true;

                       else

                            return false;

                   }

              return ax;

         }


本算法的问题:
1.穷举取值过多。不必从1~9全部取
2.成功后在递归里面不能跳出。
对问题1的改进:
1.新建3维数组A[9,9,9]
2初始判断,获取该位置可取值的范围

              for(int i=0;i<9;i++)

                   for(int j=0;j<9;j++)

                   {

                       int[] B = new int[9];

                       for(int d=0;d<9;d++)

                            B[d] = d+1;

                       if(A[i,j,0]==0)

                       {

                            for(int a=0;a<9;a++)

                            {

                                 A[i,j,0] = B[a];

                                 for(int b=0;b<9;b++)

                                 {

                                     if(b!=i)

                                          if(A[i,j,0] == A[b,j,0])

                                               B[a]=0;

                                     if(b!=j)

                                          if(A[i,j,0] == A[i,b,0])

                                               B[a]=0;

                                 }

                                 int q0 = (i/3)*3;

                                 int k0 = (j/3)*3;

                                 int q1 = (i/3+1)*3;

                                 int k1 = (j/3+1)*3;

 

                                 for(int q=q0;q<q1;q++)

                                     for(int k=k0;k<k1;k++)

                                          if(q!=i&&k!=j)

                                               if(A[i,j,0] == A[q,k,0])

                                                    B[a]=0;      

                                 A[i,j,0] = 0;

                            }

                       }

                   }

 3.更改判断部分.

         public void JudgeNumber(int x,int y)

         {

              if(x<9&&y<9)

              {

                   if(A[x,y,0] == 0||A[x,y,0] != B[x,y])

                   {

                       for(int i=1;i<9;i++)//更改部分

                       {

                            if(A[x,y,i]!=0)//更改部分

                            {

                                 A[x,y,0] = A[x,y,i];//更改部分

                                 if(Pass(x,y))

                                 {

                                     if(Victory())

                                     {

                                          printShuzu();

                                          //return ;

                                     }

                                     if(y<8)

                                          JudgeNumber(x,y+1);

                                     else

                                          JudgeNumber(x+1,0);

                                 }

                            }

                       }

                       A[x,y,0] = 0;

                   }

                   else

                   {

                       if(y<8)

                            JudgeNumber(x,y+1);

                       else

                            JudgeNumber(x+1,0);

                   }

              }

         }

posted on 2006-08-25 14:54  胡敏  阅读(10931)  评论(11编辑  收藏  举报

导航