zoukankan      html  css  js  c++  java
  • 九宫格数独--回溯法

    数独顾名思义——每个数字只能出现一次。数独是一种源自18世纪末的瑞士,后在美国发展、并在日本得以发扬光大的数字谜题。数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次。 这种游戏全面考验做题者观察能力和推理能力,虽然玩法简单,但数字排列方式却千变万化,所以不少教育者认为数独是训练头脑的绝佳方式。

    九宫格的游戏在很多地方都经常出现,比如手机,电脑等等,下面就以简单的一个例子来说明如何使用回溯算法来解决该类问题。下面数组代表最初给出的九宫格,
    0为空格需要填的数字。
    int[,] pu = new int[9, 9]
            {
            {0,0,0,7,2,8,0,0,0},
            {0,9,0,0,5,1,6,0,0},
            {0,0,0,0,6,0,0,8,2},
            {3,0,0,8,0,2,7,0,4},
            {1,7,4,0,3,0,0,2,0},
            {2,8,0,5,0,0,0,3,0},
            {0,1,0,3,0,0,2,0,0},
            {0,0,7,0,4,6,0,0,5},
            {0,0,6,1,0,0,0,4,9} };
    下面使用回溯算法来解决该类问题:
    1.验证函数如下:
    private bool IsValid(int i, int j)
            {
                int n = pu[i,j];
                int[] query=new int[9]{0,0,0,3,3,3,6,6,6};
                
                int t, u;
                for (t = 0; t < 9; t++)
                {
                    if ((t != i && pu[t, j] == n) || (t != j && pu[i, t] == n))
                        return false;
                }
    
                for (t = query[i]; t < query[i] + 3; t++)
                {
                    for (u = query[j]; u < query[j] + 3; u++)
                    {
                        if ((t != i || u != j) && pu[t, u] == n)
                            return false;
                    }
                }
                return true;
    
            }

    2.显示函数:

    private void Show()
           {
               int n=0;
             
               for (var i = 0; i < 9; i++)
               {
                   for (var j = 0; j < 9; j++)
                   {
                       Console.Write(pu[i, j] + " ");
    
                   }
                   Console.WriteLine();
               }
               Console.WriteLine("----------------------------------------------");
    
           }

    3.使用回溯算法求解:

    private void Try(int n)
           {
               if (n == 81) {//是否已经是最后一个格子
                   Show();
                   return;
               }
    
                int i = n / 9, j = n % 9;
    
               if (pu[i,j] != 0) {//如果当前格子不需要填数字,就跳到下一个格子
                   Try(n + 1);
                   return;
               }
    
               for (int k = 0; k < 9; k++) {
                   pu[i,j]++;//当前格子进行尝试所有解
                   if (IsValid(i, j))
                       Try(n + 1);//验证通过,就继续下一个
               }
    
               pu[i,j] = 0;  //如果上面的单元无解,就回溯
           }
    

    4.调用如下:

    public void Test()
            {
                Show();
                Try(0);            
            }

    实际在游戏中会有不同的游戏级别如:

    低级:要求至少有一行或一列出题时已填上5个数据,其他可以随机安排,但是每行或每列必须有数据  
    中级:要求至少有一行或一列出题时已填上4个数据,其他可以随机安排,但是每行或每列必须有数据  
    高级:要求至少有一行或一列出题时已填上3个数据,其他可以随机安排,但是每行或每列必须有数据

    所以实际中我们使用回溯不是很方便,我说下我的方法:

    1.只要一个九宫格的任意两行,两列所在列有相同的数字,那么这两行,两列交叉后该九宫格就只剩下一格,这个格子就是前面的相同数字。

    2.使用1的思想,如果一个九宫格任意两行一列,或两列一行所在行列都有相同数字,那么该九宫两行一列交叉后只剩两个格子,如果一个格子游戏已经给出
    数字,剩下的格子就是该数字了。

    3.一次类推,一行一列,0行1列等等。

    作者:生鱼片
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
        
  • 相关阅读:
    Spring Boot (20) 拦截器
    Spring Boot (19) servlet、filter、listener
    Spring Boot (18) @Async异步
    Spring Boot (17) 发送邮件
    Spring Boot (16) logback和access日志
    Spring Boot (15) pom.xml设置
    Spring Boot (14) 数据源配置原理
    Spring Boot (13) druid监控
    Spring boot (12) tomcat jdbc连接池
    Spring Boot (11) mybatis 关联映射
  • 原文地址:https://www.cnblogs.com/mq0036/p/4288557.html
Copyright © 2011-2022 走看看