zoukankan      html  css  js  c++  java
  • hdu 1426:Sudoku Killer(DFS深搜,进阶题目,求数独的解)

    Sudoku Killer

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 3723    Accepted Submission(s): 1170


    Problem Description
    自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视。
    据说,在2008北京奥运会上,会将数独列为一个单独的项目进行比赛,冠军将有可能获得的一份巨大的奖品———HDU免费七日游外加lcy亲笔签名以及同hdu acm team合影留念的机会。
    所以全球人民前仆后继,为了奖品日夜训练茶饭不思。当然也包括初学者linle,不过他太笨了又没有多少耐性,只能做做最最基本的数独题,不过他还是想得到那些奖品,你能帮帮他吗?你只要把答案告诉他就可以,不用教他是怎么做的。

    数独游戏的规则是这样的:在一个9x9的方格中,你需要把数字1-9填写到空格当中,并且使方格的每一行和每一列中都包含1-9这九个数字。同时还要保证,空格中用粗线划分成9个3x3的方格也同时包含1-9这九个数字。比如有这样一个题,大家可以仔细观察一下,在这里面每行、每列,以及每个3x3的方格都包含1-9这九个数字。

    例题:


    答案:
     
    Input
    本题包含多组测试,每组之间由一个空行隔开。每组测试会给你一个 9*9 的矩阵,同一行相邻的两个元素用一个空格分开。其中1-9代表该位置的已经填好的数,问号(?)表示需要你填的数。
     
    Output
    对于每组测试,请输出它的解,同一行相邻的两个数用一个空格分开。两组解之间要一个空行。
    对于每组测试数据保证它有且只有一个解。
     
    Sample Input
    7 1 2 ? 6 ? 3 5 8
    ? 6 5 2 ? 7 1 ? 4
    ? ? 8 5 1 3 6 7 2
    9 2 4 ? 5 6 ? 3 7
    5 ? 6 ? ? ? 2 4 1
    1 ? 3 7 2 ? 9 ? 5
    ? ? 1 9 7 5 4 8 6
    6 ? 7 8 3 ? 5 1 9
    8 5 9 ? 4 ? ? 2 3
     
    Sample Output
    7 1 2 4 6 9 3 5 8
    3 6 5 2 8 7 1 9 4
    4 9 8 5 1 3 6 7 2
    9 2 4 1 5 6 8 3 7
    5 7 6 3 9 8 2 4 1
    1 8 3 7 2 4 9 6 5
    2 3 1 9 7 5 4 8 6
    6 4 7 8 3 2 5 1 9
    8 5 9 6 4 1 7 2 3
     
    Author
    linle
     
    Source
     
    Recommend
    LL   |   We have carefully selected several similar problems for you:  1258 1045 2614 1067 1312 
     
      DFS搜索,进阶题目
      题意是给你多个数独题目,让你输出它们的答案。
      思路是递归确定每一个‘?’的位置的值,直到所有‘?’都被确定。先将原字符数组转换为整型数组,‘?’由数字0代替,然后每一次层递归找到第一个0的位置,如果找到了,找出当前位置所有可以放置的数字,依次尝试,每次假设把这个数放在当前位置,然后再确认下一个0位置的数字,直到数组中找不到0,即是正确结果(递归出口)。
      注意输入格式,要求输入的每组数据之间有一个空行,可以先单独输入第一组数据,后面的数据都是先读取空行,再读取数据。
      题目给的测试数据很弱,献上一组我的测试数据,如果你总是WA可以试试:
    ? 5 ? 4 ? 8 ? ? 2
    ? ? 1 ? ? 5 7 3 ?
    ? 6 2 ? ? 7 ? ? 9
    ? ? 8 ? 6 3 2 ? 7
    3 ? ? 1 ? ? ? ? 6
    5 ? 6 2 ? ? 9 ? ?
    4 ? ? 7 ? ? 8 2 ?
    ? 1 7 8 ? ? 3 ? ?
    2 ? ? 9 ? 1 ? 7 ?

      答案

    7 5 3 4 9 8 1 6 2
    9 4 1 6 2 5 7 3 8
    8 6 2 3 1 7 4 5 9
    1 9 8 5 6 3 2 4 7
    3 2 4 1 7 9 5 8 6
    5 7 6 2 8 4 9 1 3
    4 3 9 7 5 6 8 2 1
    6 1 7 8 4 2 3 9 5
    2 8 5 9 3 1 6 7 4

      注意如果这一步的所有情况都判定失败,返回上一层递归的时候不要忘了将当前位置还原为“?”的状态,否则会影响以后的递归。

      代码量比别人长了一些,速度也达到了400MS左右,但好在关键地方都做了注释,代码还算好懂,看官们有改进意见可以跟我提。

      不费话了,上代码

      1 #include <stdio.h>
      2 #include <iostream>
      3 using namespace std;
      4 void putoutint(int b[9][9])    //输出整型二维数组
      5 {
      6     int i,j;
      7     for(i=0;i<9;i++){
      8         for(j=0;j<9;j++)
      9             if(j!=8)
     10                 cout<<b[i][j]<<' ';
     11             else
     12                 cout<<b[i][j];
     13         cout<<endl;
     14     }
     15 }
     16 void char2int(char a[9][20],int b[9][9])    //字符二维数组向整型二维数组转换
     17 {
     18     int i,j;
     19     for(i=0;i<9;i++)
     20         for(j=0;j<18;j++)
     21             if(a[i][j]=='?')
     22                 b[i][j/2] = 0;
     23             else if('1'<=a[i][j] && a[i][j]<='9')
     24                 b[i][j/2] = a[i][j]-'0';
     25 }
     26 bool judge(int curx,int cury,int num,const int b[9][9])
     27 {
     28     int i,j;
     29     //查找一横行
     30     for(i=0;i<9;i++)    //将这一行出现的数字全部设为不可填
     31         if(i!=cury && b[curx][i]==num)
     32             return true;
     33     //查找一竖列
     34     for(i=0;i<9;i++)    //将这一行出现的数字全部设为不可填
     35         if(i!=curx && b[i][cury]==num)
     36             return true;
     37     //查找当前九宫格
     38     int x,y;
     39     x = curx/3*3;
     40     y = cury/3*3;
     41     for(i=0;i<3;i++)
     42         for(j=0;j<3;j++)
     43             if(x+i!=curx && y+j!=cury && b[x+i][y+j]==num)
     44                 return true;
     45     return false;
     46 }
     47 bool dfs(int b[9][9])
     48 {
     49     //找到当前第一个'?'位置。如果没有找到,表示所有位置都已填上,即为正确结果,递归结束
     50     int i,j;
     51     for(i=0;i<9;i++)
     52         for(j=0;j<9;j++)
     53             if(b[i][j]==0)    //找'?'的位置
     54                 goto label;            
     55     label:
     56     if(i>=9 && j>=9)    //找到正确结果了,递归结束
     57         return true;
     58     //记录坐标
     59     int curx = i,cury = j;
     60     //确定该位置的可以填的数字
     61     bool temp[10];    //记录哪些数字可以填
     62     int num=0;    //记录当前位置可以填的数字的个数
     63     for(i=1;i<=9;i++)
     64         if(judge(curx,cury,i,b))    //判断这个位置可不可以放这个数字
     65             temp[i] = false;
     66         else {
     67             temp[i] = true;
     68             num++;
     69         }
     70     if(num==0)
     71         return false;
     72     //确定下一个位置
     73     for(i=1;i<=9;i++)
     74         if(temp[i]){
     75             //这个数在这个位置可以填
     76             if(judge(curx,cury,i,b))
     77                 continue;
     78             b[curx][cury] = i;
     79             if(dfs(b))
     80                 return true;
     81         }
     82     b[curx][cury] = 0;    //这句千万别忘了写,就是这一步不能走的记得还原为0
     83     return false;
     84 }
     85 int main()
     86 {
     87     char a[9][20];
     88     int b[9][9];
     89     int i;
     90     for(i=0;i<9;i++)
     91         cin.getline(a[i],20,'
    ');
     92     char2int(a,b);    //char数组转换为int数组
     93     if(dfs(b))    //产生结果
     94         putoutint(b);    //输出数组内容
     95 
     96     while(cin.getline(a[0],20,'
    ')){    //读取空行,或者到文件尾
     97         cout<<endl;
     98         char a[9][20];
     99         int b[9][9];
    100         int i;
    101         for(i=0;i<9;i++)
    102             cin.getline(a[i],20,'
    ');
    103         char2int(a,b);    //char数组转换为int数组
    104         if(dfs(b))    //产生结果
    105             putoutint(b);    //输出数组内容
    106     }
    107     return 0;
    108 }

    Freecode : www.cnblogs.com/yym2013

  • 相关阅读:
    Unix IPC之共享内存区(1)
    linux下的二进制文件的编辑和查看
    Posix 信号量
    Unix IPC之Posix信号量实现生产者消费者
    整型信号量与记录型信号量
    C++之友元
    C++之异常处理
    C++之STL(标准模板库)
    C++之继承
    C++之封装
  • 原文地址:https://www.cnblogs.com/yym2013/p/3655469.html
Copyright © 2011-2022 走看看