zoukankan      html  css  js  c++  java
  • sudoku solver(数独)

    Write a program to solve a Sudoku puzzle by filling the empty cells.

    Empty cells are indicated by the character '.'.

    You may assume that there will be only one unique solution.

    A sudoku puzzle...

    1 每个backtracking的题目,最好都有独立判断isValid的程序,这样架构清楚。同时,valid判断函数在这里可以稍微研究一下。只要当前要判断的位置上的数值和本行没有重复,本列没有重复,九宫格没有重复就可以。一旦重复立即返回,减少判断次数。

    2 backtracking的递归函数,怎么能没有返回值呢?!因为要判断递归的方案正确与否,所以这里的递归一定是有返回值的(除非是combination那种没有正确错误概念的backtracking)!

    3 可以考虑“先放置,再判断”的方案。比如这里,首先判断当前位置是否为空,如果为空,那么放置一个元素,检查它是否正确。如果正确,就继续进行下面的递归(也就是第29行 isValid&&solveSudoku的作用)。当函数返回错误之后,将刚刚的数值变为空,再进行下一次尝试即可。

    5 最后一点需要注意的是,当i,j循环完毕之后,表明已经解出了sudoku,需要返回!切记切记,最终情况!

    简单地说思路就是循环处理子问题,对于每个格子,带入不同的9个数,然后判合法,如果成立就递归继续,结束后把数字设回空。大家可以看出代码结构和N-Queens是完全一样的。判合法其实在这里因为每次进入时已经保证之前的board不会冲突,所以不需要判断整个盘,只需要看当前加入的数字和之前是否冲突就可以,这样可以大大提高运行效率,毕竟判合法在程序中被多次调用。

    class Solution {
        public void solveSudoku(char[][] board) {
            helper(board,0,0);
        }
        //判断row,col位置是否为'.',是的话就设置值。
        //因为要判断是否正确,所以需要返回值
        public boolean helper(char[][] board,int row,int col){
            if(col>=9){  //下一个位置超出列,就是进行下一行
               return helper(board,row+1,0);
            }
            if(row==9){
                return true;
            }
            //如果该位置是'.',则要添加数字
            if(board[row][col]=='.'){
                //依次给该位置添加1-9
                for(int k=1;k<=9;k++){
                    board[row][col]=(char)(k+'0');
                    if(isValid(board,row,col)){//如果有效,就进行下一个位置添加
                        if(helper(board,row,col+1))//如果后面的添加返回true,表明添加成功,返回true,否则就尝试下一个k
                            return true;
                    }
                    board[row][col]='.';
                }
            }else{
               return helper(board,row,col+1);
            }
            return false;
        }
        /*
        前面都已经判断了,只要判断该位置添加数字后是否符合要求,也就是看该行、列有没有和该元素相同的,而且该位置所在的九宫格中也不能有和它相同的
        */
        public boolean isValid(char[][] board,int row,int col){
            //判断列是否有相同的,再同列不同行,元素却相同
            for(int i=0;i<9;i++){
                if(i!=row&&board[i][col]==board[row][col]) 
                    return false;
            }
            //判断行是否有相同的,同行不同列
            for(int j=0;j<9;j++){
                if(j!=col&&board[row][col]==board[row][j])
                    return false;
            }
            
            //判断该位置所在九宫格是否有相同的
            /*要根据该位置找到所在九宫格的行和列的范围
            每个九宫格的行的范围是0-2,3-5,6-8,
            */
            for(int i=row/3*3;i<row/3*3+3;i++)
            {
                for(int j=col/3*3;j<col/3*3+3;j++){
                    if((i!=row||j!=col)&&board[i][j]==board[row][col])
                        return false;
                }
            }
            
            return true;
        }
    }
  • 相关阅读:
    Angular Universal 学习笔记
    SAP Spartacus 如何获得当前渲染页面的 CMS 元数据
    Angular 服务器端渲染的学习笔记(二)
    Angular 服务器端渲染的学习笔记(一)
    第三方外部 Saas提供商如何跟使用 SAP 系统的客户进行对接接口集成
    如何从 SAP Spartacus Product Detail 页面,找到其 Angular 实现 Component 的位置
    具备自动刷新功能的 SAP ABAP ALV 报表
    C++学习目录
    c--条件编译
    c--文件读写--二进制
  • 原文地址:https://www.cnblogs.com/xiaolovewei/p/8320182.html
Copyright © 2011-2022 走看看