“数独”程序

1。“数独”游戏简介:

数独(日语:数独 すうどく)是一种源自18世纪末的瑞士,后在美国发展、并在日本得以发扬光大的数学智力拼图游戏。拼图是九宫格(即3格宽×3格高)的正方形状,每一格又细分为一个九宫格。在每一个小九宫格中,分别填上1至9的数字,让整个大九宫格每一列、每一行的数字都不重复。

数独的玩法逻辑简单,数字排列方式千变万化。不少教育者认为数独是锻炼脑筋的好方法。

如图:

2。算法思路: 

  (1)对于每一个数字分析所有点,如果同行,同列,同宫(宫代表3*3小格)有这个数字,则标记此点不能填此数字。如果同宫内只有一个点可以填这个数字,则填上。

  (2)如果一点的同行,同列,同宫内已经有了1-9这9个数字中的8个,则填上最后一个。

  (3)反复循环(1)(2)两步,直到通过上两个条件已无法新填入数字。

  (4)如果此时所有点都填完,找到此题的唯一解,输出,程序结束;如果此时图中仍有空点,说明此题可能有多个解。找到填入可能性较少的点,猜测一个值。之后回到步骤(1),循环。

:<1> 当可能有多个解时,此程序只输出最先找到的一个解,而不是所有解。

      <2> 如果题目已知的数字过少(如只已知一个数字,或一个都不知道,只是一张空白表),则会造成搜索空间过大。通过网上看题,可把阈值设为一张图最少要填入17个数字。

3。code

 

bool game :: analyze( int  a[][Dim])
{
    bool flag1
= true ,  flag2 = true;
        
// 遍历整表,如果通过不重分析填入过数字,则flag1置真
        
// 遍历整表,如果通过不漏分析填入过数字,则flag2置真
    
int  k ,  i ,  j;                 // i , j为循环变量 ,  k表示此格的值
    bool tag[Dim][Dim];            
// 对于一个数( 1 - 9 ) ,  判断(i , j)点上是否可以写入这个数
    bool tagRow[Dim]
,  tagLine[Dim] ,  tagSmallTable[Dim] ,  tagTotal[Dim];
        
// tagRow纪录一行中是否包含1 - 9 ,  tagLine纪录一列中是否包含1 - 9 ,
        
// tagSmall纪录3 * 3小格中是否包含1 - 9 ,  tagTotal纪录一点同行、列、 3 * 3小格三方面是否包含1 - 9
    
int  existCount;
        
// 纪录一点同行、列、 3 * 3小格三方面共包含1 - 9中9个数字其中的几个(用于回朔)


    
while (flag1  ||  flag2)
    {    
        
while (flag1)         // 不重分析
        {
            flag1 
=  false;
            
for  (k = 1 ; k <= 9 ; k ++ )
            {
                
for (i = 0 ; i < Dim; i ++ )         // tag数组全置false
                    
for  (j = 0 ; j < Dim; j ++ )
                    {
                        tag[i][j] 
=  false;
                    }

                
for  (i = 0 ; i < Dim; i ++ )         // 察看对所有点来说哪些点可以填入数字k        
                    
for  (j = 0 ; j < Dim; j ++ )
                    {
                        
// 如果(此点无数  &&  同行没有k  &&  同列没有k  &&  所在3 * 3格没有k) 则此点可写入k
                        
if  (a[i][j] == 0   &&  rowExist(a ,  i ,  k) == false  &&  lineExist(a ,  j ,  k) == false
                           
&&  smallTableExist(a ,  i ,  j ,  k) == false)
                           tag[i][j] 
=  true;
                    }
                
                
for  (i = 0 ; i < Dim; i ++ )         // 对于一个3 * 3格内如果只有一个点可以填入数字k ,  则填入
                    
for  (j = 0 ; j < Dim; j ++ )
                    {
                        
if  (tag[i][j] == true 
                            
&&  smallTableDoubleExist(tag ,  i ,  j) == false)
                        {
                            a[i][j] 
=  k;
                            flag1 
=  true;     // 如果此次循环有内容写入,则flag1置真
                            break;
                        }
                    }                
            }
// end  for (k)
        }
// end  while (flag1)


        
while (flag2)         // 不漏分析,查看此点所在的行、列、小格中是否包含1 - 9
        {                        
            flag2 
=  false;
            
for  (i = 0 ; i < Dim; i ++ )
                
for  (j = 0 ; j < Dim; j ++ )
                {
                    
for  (k = 0 ; k < 9 ; k ++ )
                        tagRow[k] 
=  false;
                    
for  (k = 0 ; k < 9 ; k ++ )
                        tagLine[k] 
=  false;
                    
for  (k = 0 ; k < 9 ; k ++ )
                        tagSmallTable[k] 
=  false;
                    
for  (k = 0 ; k < 9 ; k ++ )
                        tagTotal[k] 
=  false;
                    existCount 
=   0 ;

                    
if  (a[i][j] == 0 )         // 如果此点无值
                    {                            
                        checkRow(a
,  i ,  j ,  tagRow);
                        checkLine(a
,  i ,  j ,  tagLine);
                        checkSmallTable(a
,  i ,  j ,  tagSmallTable);
                        checkTotal(tagRow
,  tagLine ,  tagSmallTable ,  tagTotal);
                        existCount 
=  existCounting(tagTotal);
                        
if  (existCount == 8 )     // 如果此点无值并且其同行、列、 3 * 3小格内已有1 - 9中9个数字的8个
                        {
                            a[i][j] 
=  filllast(tagTotal);     // 那么此点填入最后一个数字
                            flag2 
=  true;                
                            break;
                        }
                    }
                }
        }
// end  while (flag2)
    }
// end  while (flag1  ||  flag2)


    
/*  查看经过上面一轮填入后表内是否还存在空点,如果还存在空点,说明下面内容需要猜测
    同时也说明此题可能有多个解(此程序之给出多个解中的一个解,而不是所有解) 
*/     
    bool zeroExist;            
    zeroExist 
=  false;
    
for  (i = 0 ; i < Dim; i ++ )
    {
        
for  (j = 0 ; j < Dim; j ++ )
        {
            
if  (a[i][j] == 0 )
            {
                zeroExist 
=  true;
                break;
            }
        }
        
if  (zeroExist)
        {
            break;
        }
    }

    
if  (zeroExist)
    {
        
int  maxExistCount  =   1 ;
        
int  tempi = 0 ,  tempj = 0 ;    
        
for  (i = 0 ; i < Dim; i ++ )
            
for  (j = 0 ; j < Dim; j ++ )
            {
                
for  (k = 0 ; k < 9 ; k ++ )
                    tagRow[k] 
=  false;
                
for  (k = 0 ; k < 9 ; k ++ )
                    tagLine[k] 
=  false;
                
for  (k = 0 ; k < 9 ; k ++ )
                    tagSmallTable[k] 
=  false;
                
for  (k = 0 ; k < 9 ; k ++ )
                    tagTotal[k] 
=  false;
                existCount 
=   0 ;

                
if  (a[i][j] == 0 )
                {
                    checkRow(a
,  i ,  j ,  tagRow);
                    checkLine(a
,  i ,  j ,  tagLine);
                    checkSmallTable(a
,  i ,  j ,  tagSmallTable);
                    checkTotal(tagRow
,  tagLine ,  tagSmallTable ,  tagTotal);
                    existCount 
=  existCounting(tagTotal);
                    
if  (existCount > maxExistCount)     // 找出猜测时有较少可能性的点作为突破口
                    {
                        maxExistCount 
=  existCount;
                        tempi 
=  i;
                        tempj 
=  j;
                    }
                }                
            }

        
int  b[Dim][Dim];
        
int  c[Dim][Dim];
        
for  (k = 0 ; k < 9 ; k ++ )
            tagRow[k] 
=  false;
        
for  (k = 0 ; k < 9 ; k ++ )
            tagLine[k] 
=  false;
        
for  (k = 0 ; k < 9 ; k ++ )
            tagSmallTable[k] 
=  false;
        
for  (k = 0 ; k < 9 ; k ++ )
            tagTotal[k] 
=  false;
        existCount 
=   0 ;
        
for  (i = 0 ; i < Dim; i ++ )
            
for  (j = 0 ; j < Dim; j ++ )
                b[i][j] 
=  a[i][j];
        checkRow(a
,  tempi ,  tempj ,  tagRow);
        checkLine(a
,  tempi ,  tempj ,  tagLine);
        checkSmallTable(a
,  tempi ,  tempj ,  tagSmallTable);
        checkTotal(tagRow
,  tagLine ,  tagSmallTable ,  tagTotal);
        existCount 
=  existCounting(tagTotal);
        
if  (existCount == 9 )
        {            
            
return  false;     // 说明上一个猜测处猜错,回朔
        }
        
else  
        {
            
for  (i = 0 ; i < Dim; i ++ )     // 对于需要猜测点的各种可能性全部循环
            {
                
if  ( ! tagTotal[i])
                {
                    
int  m ,  n;         // 纪录下此时内容,在猜错后回朔时用到
                    
for  (m = 0 ; m < Dim; m ++ )
                        
for  (n = 0 ; n < Dim; n ++ )
                            c[m][n] 
=   0 ;
                    
for  (m = 0 ; m < Dim; m ++ )
                        
for  (n = 0 ; n < Dim; n ++ )
                            c[m][n] 
=  b[m][n];

                    b[tempi][tempj] 
=  i + 1 ;

                    
if  ( ! analyze(b))     // 递归,如果analyze(b)为假,说明猜错,恢复现场
                    {
                        
for  (m = 0 ; m < Dim; m ++ )
                            
for  (n = 0 ; n < Dim; n ++ )
                                b[m][n] 
=  c[m][n];
                    }
                }
            }
            
return  false;     // 如果i超出了Dim也说明前面猜测猜错了
        }    
    }
    
else      // 表中不存在0了,说明全部填完了
    {
        std
:: cout << std :: endl << " 结果为:  " << std :: endl;    
        showtable(a);
        std
:: cout << std :: endl << " 输入任意字符后按enter键结束 " ;
        char screenStop;        
// 让程序屏幕停住
        std
:: cin >> screenStop;
        
exit ( 0 );     // 程序出口
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值