`
128kj
  • 浏览: 609440 次
  • 来自: ...
社区版块
存档分类
最新评论

回溯法入门学习之二(九宫格与数独)

阅读更多
   回溯法的基本做法是搜索解空间,一种组织得井井有条的,能避免不必要搜索的穷举式搜索法。上文“回溯法入门学习之一”http://128kj.iteye.com/blog/1722216中已给出了一个框架:

"深度优先搜索+回溯"递归框架:
函数DFS(节点){
  如果(节点=目标节点) {找到目标,跳出}
  遍历所有下一层节点for(int i=0;i<k;i++){
   标记下一层节点i已访问;
   DFS(下一层的节点i)
   恢复i为未访问
  }

}

下面使用上面框架再解一例(数独问题):


题目大意,如上图(一):
    把一个9行9列的网格,再细分为9个3*3的子网格,要求每行、每列、每个子网格内都只能使用一次1~9中的一个数字,即每行、每列、每个子网格内都不允许出现相同的数字。空格是待填位置,其他均为已填入的数字。

要求填完九宫格并输出(如果有多种结果,则只需输出其中一种),
如果给定的九宫格无法按要求填出来,则输出原来所输入的未填的九宫格。
  如上图一中的9个子网络,我们假设子网格的序号如下编排图(二):

先讨论一下上图(一)中第i行j列的数字是属于哪个子网格的,
由于0<=i、j<=8,我们有图(三):



令a= i/3 , b= j/3 ,根据九宫格的行列与子网格(grid)的关系,我们有图(四):


不难发现 3a+b=k,即 3*(i/3)+j/3=k。即图一中第i行j列的数字,属于第k个子网络

算法分析: DFS+回溯
      1.把所有空格位置找出来,对他们进行dfs填补(用1,2,3,...9去试填)
      2.剪枝方法(九宫格中已有数字的不用试填),把搜索过的相应位置搜索完复位


样例:
Sample Input

1
103000509
002109400
000704000
300502006
060000050
700803004
000401000
009205800
804000107

Sample Output

143628579
572139468
986754231
391542786
468917352
725863914
237481695
619275843
854396127

import java.util.Scanner;

public class Main{
 private int table[][];//用一个二维数组表示九宫格
 private int pos[];//记录要填的空格位置
 private int posNum;//要填的空格标号(从0开始)
 private boolean rUsed[][];//rUsed[i][x]  标记在第i行中数字x是否出现了

 private boolean cUsed[][];//cUsed[j][y]  标记在第j列中数字y是否出现了

 private boolean sUsed[][];//sUsed[k][x] 标记在第k个3*3子格中数字z是否出现子
 private boolean finish_dfs;//是否已找到了答案

 public void go(){
  Scanner  in=new Scanner(System.in);
  int cnt=in.nextInt();
 
  while((cnt--)!=0){
    //初始化数据
    posNum = 0;
    pos=new int[90];
    table=new int[9][9];
    rUsed=new boolean[9][10];
    cUsed=new boolean[9][10];
    sUsed=new boolean[9][10];
    String line=null;
    
    finish_dfs = false;
    for(int i=0;i< 9;i++){ //准备输入数据
        line=in.next();
	for(int j=0;j< 9;j++){
          table[i][j]=line.charAt(j)-'0';
          if (table[i][j]!=0 ) {
             rUsed[i][table[i][j]] = true;//table[i][j]这个数字在i行中已有了
             cUsed[j][table[i][j]] = true;
             int k = (i/3)*3+(j/3);
             sUsed[k][table[i][j]] = true;//table[i][j]这个数字在第k个小网络中已有了
          }
          else {
               pos[posNum++] = i*9+j;//记录要填的空格位置及标号
          }
       }
      }
    dfs_sudoku(0);
   }
  }
   
   
 private void outre(){//输出结果
    for ( int i = 0; i < 9; i++ ) {
        for ( int j = 0; j < 9; j++ ) {
            System.out.printf( "%d", table[i][j] );
        }
         System.out.println();
     }
    //System.out.println();
  }

  void dfs_sudoku( int n ){//深度优先搜索+回溯,试填第n个空格)
    if ( n >= posNum ) {
         finish_dfs = true;
         outre();
        return;
    }
    //根据要填的空格位置,计算空格的所在的行,列坐标及处在哪个小网络
    int r = pos[n]/9;//空格的行坐标
    int c = pos[n]%9;//空格的列坐标
    int s = (r/3)*3+(c/3);//小网络的标号
    for ( int i = 1; i <= 9 && !finish_dfs; i++ ) {//用1,2,3...9去试填)
        if ( rUsed[r][i] ) continue;//第r行有i
        if ( cUsed[c][i] ) continue;//第c列有i
        if ( sUsed[s][i] ) continue;//第k个小网络有i
        rUsed[r][i] = cUsed[c][i] = sUsed[s][i] = true;
        table[r][c] = i;//第r行c列试填数字i
        dfs_sudoku( n+1 );//递归试填第n+1个空格,成功或失败,如果成功则输出,失败则回溯
        table[r][c] = 0;//回溯
        rUsed[r][i] = cUsed[c][i] = sUsed[s][i] = false;
     }
    return;
  }

  public static void main(String[] args){
    Main ma=new Main();
    ma.go();
   
  }
}
  • 大小: 15.3 KB
  • 大小: 3.6 KB
  • 大小: 18.3 KB
  • 大小: 15.3 KB
0
0
分享到:
评论

相关推荐

    九宫格VB测试

    - 九宫格游戏的核心算法是回溯法。该算法尝试填充空单元格,并检查是否符合数独的规则:每一行、每一列以及每一个3x3的小宫格内,数字1到9都只出现一次。 - 在VB中,可以使用二维数组来表示九宫格的状态,数组的每...

    九宫格游戏,带自动解题

    【九宫格游戏与C#编程】 九宫格游戏,又称数独,是一种逻辑推理类的益智游戏。它的规则简单但挑战性强,玩家需要在9x9的网格中填入数字,使得每一行、每一列以及每一个3x3的小宫格内的数字都从1到9不重复。这个游戏...

    数独技巧完全手册下载

    1. **基础规则**:数独盘面是一个9x9的大方格,分为9个3x3的小九宫格。目标是填入数字1到9,使得每一行、每一列以及每个小九宫格内的数字都不重复。 2. **初级技巧**: - **唯一候选数法**(或称为唯一解法):...

    android入门的数独小游戏

    数独游戏是一款广受欢迎的逻辑解谜游戏,它基于9×9的网格,玩家需要填入数字1到9,使得每一行、每一列以及每一个宫(3×3的小格)都包含这九个数字且不重复。在Android平台上开发数独小游戏,是学习Android应用开发...

    杀手数独题目.doc

    杀手数独的规则与传统数独类似,即每一行、每一列以及每一个小九宫格都必须包含1到9的所有数字,且每个数字只能出现一次。但杀手数独增加了额外的规则,即每个数字的杀手线索必须正确无误地反映出其出现的次数。这...

    数独题目_难度系数2.doc

    数独游戏的目标是在一个由九个小九宫格组成的大九宫格中,填入数字1到9,确保每一行、每一列以及每一个3x3的小宫格内的数字都不重复出现。这些数字填入的规则看似简单,但实际玩起来却需要缜密的逻辑思维和细致的...

    易语言数独解答器源码-易语言

    在数独解答器中,就需要频繁地操作二维数组,包括读取和修改单元格的值,以及检查每一行、每一列和九宫格内是否满足数独的规则。易语言中的数组处理功能允许我们高效地执行这些任务,为数独解答提供支持。 进阶教程...

    sudoku:可玩的数独游戏,用Python编写,具有一种算法,可在O(n ^ 2)时间内检查玩家解决方案的有效性

    数独是一种广受欢迎的逻辑推理游戏,它基于一个9×9的网格,被分为9个3×3的小九宫格。每个小九宫格、每一行、每一列都必须填入1到9的数字,且每个数字在每个区域中只能出现一次。"sudoku"项目是用Python编程语言...

    noip2009复赛提高组题解 与 A*算法

    为了提高效率,可以使用位运算来快速计算行、列和小九宫格的可填数集交集。然而,这种优化方法依然无法解决所有数据。更进一步的优化策略是优先搜索可填数字较少的格子,以减少无效的分支。 总结来说,NOIP2009复赛...

Global site tag (gtag.js) - Google Analytics