数独
来源:互联网 发布:java gzip 压缩 编辑:程序博客网 时间:2024/05/02 02:35
废话少说,先上程序(直接将代码copy到一个All的java文件中,删除package即可运行,答案将显示到控制台):
Tip:sourceInput为数独的初始状态,可以自行更改
package mySuduku;import java.util.ArrayList;import java.util.List;public class All { public static void main(String args[]){ /* * 初始数据(map) */ int sourceInput[][]={ {0,0,7,0,5,0,0,0,0}, {6,0,0,2,0,1,7,0,0}, {0,1,2,0,0,0,4,0,8}, {3,2,4,0,0,0,1,0,0}, {0,0,0,0,0,0,0,0,0}, {0,0,0,0,6,0,8,0,0}, {0,0,0,5,0,0,3,0,0}, {7,0,0,8,0,0,0,4,0}, {8,4,0,0,0,3,5,7,0}}; /* 用来分析的map * 后期可以填补,以便简化map */ int inputMap[][]=new int[9][9]; /* * 分析使用的map(使map不能再优化) * analyInputMap[x][y][z]中xy对应inputMap[x][y],[z]中1-9代表1-9的可能性, * 10代表这个数是否在原map中已经存在 */ int analyInputMap[][][]=new int[9][9][10]; //与分析的map做比较用的 int tempAnalyMap[][][]=new int[9][9][10]; //比较两个map(这个看是否是优化为最终结果) boolean compareInputToTemp=true; //将sourceInput塞入inputMap中 setSameMap(sourceInput,inputMap,9,9); /* * 去除inputMap中有的值 * 即置analyInputMap[x][y][z]中的z位为该数(map[x][y])不可用 */ deleteFromMap(sourceInput,analyInputMap); /* * 两步删除不可能的结果 * 两步分别指: 1对所有剩下的空白格,求出其可能的数值, * 2当其可能数值仅有一种时,更新inputMap填上这一种,然后将analyInputMap进行调整 * 当输入和输出的值一样的时候认为无法再进一步简化 */ while(compareInputToTemp){ //赋值inputMap到tempMap setSameMap(analyInputMap,tempAnalyMap,9,9,10); //检查是否可以进一步简化 arrange(inputMap,analyInputMap); //判断上步简化是否确实发生了变化 compareInputToTemp=compareAB(analyInputMap,tempAnalyMap,9,9,10); printMap(inputMap,9,9); printMap(analyInputMap,9,9,9); } /* * while后结果可视为初步最优解,此时考虑遍历所有剩下的可能情况,用countRest记录剩余空白格 * 对每个空白格需记录这么几个项:1坐标(即x,y),2可能的数字 * 这里采用一个类(theRest)记录 * 类中的X,Y记录坐标,avaiable记录可能的数值 * * 最后,用List<theRest> theRestNumber装下所有theRest */ //剩下还有多少空没有填 int countRest=0; //每个填的数字需要用个数据结构(类theRest) List<theRest> theRestNumber=new ArrayList<theRest>(); //一个暂时的temp指针,指向一个theRest类,这里先设置了,减小开销 theRest temp; for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(inputMap[i][j]==0){ countRest++; temp=new theRest(i,j); for(int k=0;k<9;k++){ if(analyInputMap[i][j][k]==0) temp.avaiable.add(k+1); } theRestNumber.add(temp); } //试试一个数字 tryANumber(inputMap,countRest,countRest,theRestNumber); } /* * 试试一个number * 整体思路如下,输入参数为map(最终优化后结果),计数,整体theRestNumber的length,theRestNumber * 出口就是填满所有数字(由于是先检查,再填数字,所以最后不用检查) */ public static void tryANumber(int[][] map,int nowRest,int allRestNum,List<theRest> theRestNumber){/* printMap(map,9,9);*/ if(nowRest==0){ printMap(map,9,9); } else if(allRestNum-nowRest>=0&&allRestNum!=0){ theRest temp=theRestNumber.get(allRestNum-nowRest); boolean flag=false; int i; for(i=0;i<temp.avaiable.size();i++){ flag=check(map,temp,temp.avaiable.get(i)); //如果值是可用的,则将值放入,并进行下一次的迭代 if(flag) { map[temp.x][temp.y]=temp.avaiable.get(i); tryANumber(map,nowRest-1,allRestNum,theRestNumber); //当try遍历完成后,将尝试的值置空 map[temp.x][temp.y]=0; } } } } //检查放入一个number以后是否可行 public static boolean check(int[][] map,theRest temp,int tryNumber){ boolean flag=true; //检查横行和竖行是否有数字已经要尝试的数字了 for(int i=0;i<9;i++) if(map[temp.x][i]==tryNumber||map[i][temp.y]==tryNumber) flag=false; //排除坐标对应3*3格中有没有尝试的数字 int tempx=temp.x/3; int tempy=temp.y/3; for (int i=0;i<3;i++) for(int j=0;j<3;j++) if(map[tempx*3+i][tempy*3+j]==tryNumber) flag=false; return flag; } //从分析的map中删除map中有的元素(即置标签位(z=9)为空) public static void deleteFromMap(int[][] source,int[][][] target){ for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(source[i][j]!=0) target[i][j][9]=1; }; /* * 安置函数,入参是inputMap,和analyInputMap * 当a(即inputMap)每出现一个数字时,在对应的b(即analyInputMap)中进行相应动作(controlB) * 该动作排除a出现后限制b中的可能性(即a中空白处对应的可能数字要相应减少) * 在动作后,对b经行遍历,发现若a的空白处可填项仅有一个时,对a进行填项,填项后对b的该坐标位置不可填 */ public static void arrange(int[][] a,int[][][]b){ for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(a[i][j]!=0) controlB(i,j,a[i][j],b); //是否a的空白出只有一个可填项 int countIsOnly; //对b经行遍历,发现若a的空白处可填项仅有一个时,对a进行填项,填项后对b的该坐标位置不可填 for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(a[i][j]==0&&b[i][j][9]!=1){ countIsOnly=9; //循环,发现1则减去,当8个1时,说明只有一个可填,填项 for(int k=0;k<9;k++) countIsOnly-=b[i][j][k]; if(countIsOnly==1){ for(int k=0;k<9;k++) if(b[i][j][k]==0) a[i][j]=k+1; b[i][j][9]=1; } } } public static void controlB(int x,int y,int value,int[][][] b){ for(int i=0;i<9;i++){ //排除每行第x个字 b[x][i][value-1]=1; //排除每列第x个字 b[i][y][value-1]=1; } //排除坐标对应的3*3格 int tempx=x/3; int tempy=y/3; for (int i=0;i<3;i++) for(int j=0;j<3;j++){ b[tempx*3+i][tempy*3+j][value-1]=1; } } //复制二维数组函数,不多说 public static void setSameMap(int[][]source,int[][]target,int x,int y){ for(int i=0;i<x;i++) for(int j=0;j<y;j++) target[i][j]=source[i][j]; } //复制三位数组函数,不多说 public static void setSameMap(int[][][]source,int[][][]target,int x,int y,int z){ for(int i=0;i<x;i++) for(int j=0;j<y;j++) for(int k=0;k<z;k++) target[i][j][k]=source[i][j][k]; } //比较二维数组函数,不多说 public static boolean compareAB(int[][]a,int[][] b,int x,int y){ boolean flag=true; for(int i=0;i<x;i++) for(int j=0;j<y;j++) if(b[i][j]!=a[i][j]) flag=false; return flag; } //比较三维数组函数,不多说 public static boolean compareAB(int[][][]a,int[][][] b,int x,int y,int z){ boolean flag=false; for(int i=0;i<x;i++) for(int j=0;j<y;j++) for(int k=0;k<z;k++) if(b[i][j][k]!=a[i][j][k]) flag=true; return flag; } //打印二维map,不多说 public static void printMap(int[][] map,int x,int y){ for(int i=0;i<x;i++){ System.out.println(); for(int j=0;j<y;j++){ System.out.print(map[i][j]+" "); } } System.out.println(); } //打印三维map,不多说 public static void printMap(int[][][] map,int x,int y,int z){ for(int i=0;i<x;i++){ System.out.println(); for(int j=0;j<y;j++){ if(map[i][j][9]!=1){ System.out.print("map【"+i+"】:"+"【"+j+"】:"); for(int k=0;k<9;k++){ if(map[i][j][k]!=1) System.out.print(k+1); System.out.print(" "); } } } } System.out.println(); }} /* * 一个简单类,用装剩余空白格的信息 * x,y记录空白处的坐标 * avaiable记录可填充的数字 */class theRest{ public int x; public int y; public List<Integer> avaiable=new ArrayList<Integer>(); public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public theRest(int x, int y) { super(); this.x = x; this.y = y; }}
程序总体思路:
1输入状态
2解决
2.1 将总体状态放入一个sourceInput[9][9]
2.2 优化sourceInput,用inputMap[9][9]存放最后优化结果
2.2.1 优化,以下步骤
- 当map中每出现一个数,在其余的横竖和对应的3*3格子内不允许出现该数字,注意剩下的空白格子中可填的数字,
- 当空白格子中可填数字仅剩一个时,填入该数字,
- 重复上两步,直到map不再发生变动
2.3 对于优化的结果,可记num个空格,每个空格的可能填的数字可能个数记为an,则此时全遍历的情况为a1*a2*a3*…*an(n=num),
2.4 这里采用思想是深度遍历,当遇到结果就打印,然后继续下一步,直到遍历完(以防止多解情况)
3输出答案
Ps:这里仅是一次尝试,还有好多不妥之处,还望见谅~
0 0
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- 数独
- iOS小数去除末位无效零问题
- java并发:内置锁 synchronized
- kube-proxy源码分析
- 常见算法问题之最长公共子串问题(Longest common substring problem)
- SDN开发实战(1)-透明HTTP代理[Openflow+floodlight]
- 数独
- Python爬虫实战(一)
- TOMCAT启动闪退
- hash_map,unordered_map的使用
- Jump Game
- javascript原型
- 进度条小程序
- python 中函数format()函数进行字符串格式化
- 第7章 流程控制