zoukankan      html  css  js  c++  java
  • 利用程序随机构造N个已解答的数独棋盘

      1 package sudoku;
      2 public class shudu {
      3     static int [][]n=new int[9][9];
      4     static int[] num={1,2,3,4,5,6,7,8,9};
      5     public static void main(String[] srgs){
      6         // TODO 自动生成的方法存根
      7         for(int i=0;i<9;i++){   //生成数字
      8             int time=0;        //记录填充数字的次数
      9             for(int j=0;j<9;j++){    //填充数字
     10                 n[i][j]=generateNum(time);   //产生数字
     11                 if(n[i][j]==0){    //如果返回是的0,说明此时出现重复数字,不能进行数字填充,要进行回溯
     12                     if(j>0){      //回溯原则:如果不是该行的第一格,则往左退一格,否则退到上一行的最后一格
     13                         j-=2;    // 不是该行的第一格,则往左退一格
     14                         continue;
     15                     }
     16                     else{      
     17                         i--;  //是该行的第一格,退到上一行的最后一格
     18                         j=8;
     19                         continue;
     20                     }
     21                 }      //数字填充成功
     22                 if(isCorret(i,j)){
     23                     time=0;  //对数字填充的次数进行初始化,为下一次填充进行做准备
     24                 }
     25                 else{
     26                     time++;   //继续填充,填充次数+1
     27                     j--;     //继续填充该行剩下的格子
     28                 }
     29             }        
     30         }    //对数独填充完毕后,将数独进行输出
     31         for(int i=0;i<9;i++){
     32             for(int j=0;j<9;j++){
     33                 System.out.print(n[i][j]+" ");
     34             }
     35             System.out.println();
     36         }        
     37     }
     38     private static int generateNum(int time) {  //产生1-9的随机数字,随机数字生成规则:利用Random函数生成随机数字,生成的随机数字是存放在数组8-time下标的位置
     39         // TODO 自动生成的方法存根
     40         if(time==0){    //第一次尝试,对随机数字源组进行初始化操作
     41             for(int i=0;i<9;i++){
     42                 num[i]=i+1;// 生成随机数字,该数字是数组的下标,取数组num中该下标对应的数字为随机数字
     43             }
     44         }       
     45         if(time==9){   //第十次尝试,说明该位置没有符合条件的数字,则返回0,由主程序进行回溯操作
     46             return 0;
     47         }     
     48         //随着time的增加,前面试过的数字将不会再取到,因为第一次的数字是在生成随机数字中随机选择的,第二次则是在剩下的随机数字中进行选择,以此类推……
     49         int ranNum=(int)(Math.random()*(9-time)); //把数字放置在数组倒数第time个位置
     50         int temp=num[8-time];
     51         num[8-time]=num[ranNum];
     52         num[ranNum]=temp;
     53         return num[8-time];  
     54     }
     55     public static boolean isCorret(int row,int col){   //在填充过程中,对填充的数字进行判断是否合法,对该行、该列、该宫是否出现重复数字
     56         return(checkRow(row)&checkLine(col)&checkGong(row,col));    
     57     }
     58     private static boolean checkGong(int row, int col) {    //在填充过程中,对该宫填充的数字进行判断是否合法,是否有重复数字出现
     59         // TODO 自动生成的方法存根
     60         int j=row/3*3;    //获取该格的坐标
     61         int k=col/3*3;
     62         for(int i=0;i<8;i++){    //在该宫内进行循环比较
     63             if(n[j+i/3][k+i%3]==0){
     64                 continue;
     65             }
     66             for(int m=i+1;m<9;m++){
     67                 if(n[j+i/3][k+i%3]==n[j+m/3][k+m%3]){
     68                     return false;    //返回false代表不合法
     69                 }
     70             }
     71         }
     72         return true;  //返回true代表合法
     73     }
     74     private static boolean checkLine(int col) {  //在填充过程中,对该列填充的数字进行判断是否合法,是否有重复数字出现
     75         // TODO 自动生成的方法存根
     76         for(int j=0;j<8;j++){
     77             if(n[j][col]==0){
     78                 continue;
     79             }
     80             for(int k=j+1;k<9;k++){
     81                 if(n[j][col]==n[k][col]){
     82                     return false;     //返回false代表不合法
     83                 }
     84             }
     85         }
     86         return true;     //返回true代表合法
     87     }
     88     private static boolean checkRow(int row) {   //在填充过程中,对该行填充的数字进行判断是否合法,是否有重复数字出现
     89         // TODO 自动生成的方法存根
     90         for(int j=0;j<8;j++){
     91             if(n[row][j]==0){
     92                 continue;
     93             }
     94             for(int k=j+1;k<9;k++){
     95                 if(n[row][j]==n[row][k]){
     96                     return false;  //返回false代表不合法
     97                 }
     98             }
     99         }
    100         return true;   //返回true代表合法
    101     }        
    102 }

    以上是全部代码,附上几个生成的数独:

    2 9 8 1 5 6 7 3 4 

    6 7 1 8 4 3 5 2 9 

    3 4 5 2 7 9 8 6 1 

    8 1 9 6 3 7 4 5 2 

    4 2 6 5 8 1 9 7 3 

    7 5 3 9 2 4 1 8 6 

    1 3 2 7 9 5 6 4 8 

    5 6 4 3 1 8 2 9 7 

    9 8 7 4 6 2 3 1 5 

    ------------------

    5 2 7 9 3 4 1 6 8 

    1 9 6 8 2 5 4 3 7 

    3 4 8 7 1 6 5 2 9 

    9 7 3 4 5 2 8 1 6 

    6 8 2 1 7 9 3 5 4 

    4 5 1 3 6 8 7 9 2 

    2 3 4 6 8 1 9 7 5 

    7 6 9 5 4 3 2 8 1 

    8 1 5 2 9 7 6 4 3 

    ------------------

    7 3 9 8 2 5 4 1 6 

    6 5 4 7 9 1 3 2 8 

    2 8 1 3 4 6 5 9 7 

    1 9 6 2 8 4 7 3 5 

    8 7 5 6 3 9 1 4 2 

    4 2 3 5 1 7 6 8 9 

    3 1 7 9 5 8 2 6 4 

    9 6 2 4 7 3 8 5 1 

    5 4 8 1 6 2 9 7 3 

    分析:该程序正确,能正确输出数独,能达到题目要求,可输出百万级别的数独;该程序代码量较少,能在0.3856秒内输出结果,性能较好。

    心得:本次作业中,花了一天和2个晚上才做完,一开始在网上进行资料查询,对什么是数独进行了解,然后也查了一下别人是怎么实现的,总体来说,本题有3种方法(自认为,或许还有很多,只是我不知道而已),第一种就是从第一宫的第一格开始填数,从左到右从上往下进行填数,每填一个数就对该数所在行、列、宫进行检查该数是否合法,如果不合法,就进行回溯,重新填写,一直循环,循环到填满9个宫;第二种就是在每个宫中进行随机填写一个相同的随机数,然后对填的数所在行、列、宫进行检查该数是否合法,如果不合法,就进行回溯,重新填写,一直循环,循环到填满9个宫为止;第三种就是先对数独的两条对角线进行填充,然后按照第一种方法进行填充,一直到填满为止。以上3种方法,各有各的优点,我所选的方法是第一种,我猜大部分人应该是第一种,因为这个是比较容易想到的,在进行回溯的过程中,是按照以下规则进行回溯,回溯原则:如果不是该行的第一格,则往左退一格,否则退到上一行的最后一格。

    在做本次作业中,对自己的编程能力是一种锻炼,我以前编程能力较为欠缺,通过这次作业,对我的编程能力有一定的提高,特别是在思考题目过程中,自己思维能力的提升是最明显的,对问题的考虑也比以前更加细致,对题目中所能出现的问题也考虑的更加全面,在本次题目中遇到的问题便是怎么进行回溯,回溯的规则是怎样的,经过自己的努力,终于把这个问题想清楚了,然后通过编程将其实现。在做数独题目过程中,本算法较为快速的原因在于产生1-9的随机数字,本题中随机数字生成规则:利用Random函数生成随机数字,生成的随机数字是存放在数组8-time下标的位置,这样可以保证前面填充的数字不会再拿出来进行填充,就可以省下对不符合要求数字的尝试时间,大大提高程序的运行时间,不这样做,虽然也能做出来,但是运行速度可能会打折扣。

    本次做题的收获便是想到什么不动手去实现是没用的,想出来觉得很简单,可实际并不一定,只有你通过自己行动把它实现了才知道容不容易,勤思考,多行动,付出实践的思考才是有用的思考。

    课外任务作业:从链接的调查表中发现,我觉得:语言、需求分析、项目管理、团队协作、理论素养这5部分对我个人来说比较重要,语言学了不下于10种,却没有一个精通的,简言之“多而不精”;需求分析方面,对软件所需要考虑的各方各面考虑的还不是很清楚,导致做出来的APP有很多bug,或者一些功能不尽人意;项目管理方面,带过好几个项目,最终都勉强完成,但是没有达到自己想要的结果;团队协作方面自认为还可以;理论素养还得继续加强。希望这门课程结束后,自己能有所提高这几方面。

  • 相关阅读:
    TControl的主要功能研究(属性,函数,事件)
    写一个控件,如何实现设计期的可视化
    Delphi 通过脚本 在 设计期 改 控件name 属性
    Delphi TreeView – 自动展开树形结构
    Delphi之创建组件模板(Component Template)
    delphi Controls Components 属性
    Delphi 2009 之 TCategoryPanelGroup[1]: ChevronAlignment 等
    delphi xe 10分组按钮CategoryButtons 折叠按钮
    Delphi ControlCount和ComponentCount的区别
    ComponentCount和ControlCount区别
  • 原文地址:https://www.cnblogs.com/AnanKing/p/9745678.html
Copyright © 2011-2022 走看看