2020-10-16

Java解数独效率提升方法

参考:深度搜索(递归)
虽说Java的运算速度确实快,但追求算法和提速是永恒的主题。
不满来自以下情况:

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

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

程序运行时间:5.2010000000000005s

程序修订后,上述数独的破解从原来的5秒左右,提升到0.041秒,是一个巨大的进步。
修订思路:
1、对数独中的0的个数进行统计,在此基础上对可填数字的数量进行统计。
2、优先处理当前可填数字最少的那个0,优化深度搜索策略。

package good;

import java.util.Scanner;

public class sd {
	
	static int[][] arr1={{8, 0, 0, 0, 0, 0, 0, 0, 0},
			            {0, 0, 3, 6, 0, 0, 0, 0, 0},
	                    {0, 7, 0, 0, 9, 0, 2, 0, 0},
	                    {0, 5, 0, 0, 0, 7, 0, 0, 0},
	                    {0, 0, 0, 0, 4, 5, 7, 0, 0},
	                    {0, 0, 0, 1, 0, 0, 0, 3, 0},
	                    {0, 0, 1, 0, 0, 0, 0, 6, 8},
	                    {0, 0, 8, 5, 0, 0, 0, 1, 0},
	                    {0, 9, 0, 0, 0, 0, 4, 0, 0}};
	static int[][] arr2={{0, 0, 0, 0, 0, 2, 0, 5, 0},
                        {0, 7, 8, 0, 0, 0, 3, 0, 0},
                        {0, 0, 0, 0, 0, 4, 0, 0, 0},
                        {5, 0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 1, 0, 0},
                        {0, 0, 0, 0, 3, 0, 7, 0, 8},
                        {2, 0, 0, 0, 0, 0, 0, 4, 0},
                        {0, 0, 0, 0, 0, 5, 0, 9, 0},
                        {0, 1, 0, 0, 7, 0, 0, 0, 0}};
    static int[][] arr3={{0, 0, 0, 0, 0, 0, 0, 0, 0},
						 {0, 6, 0, 3, 0, 4, 0, 2, 0},
						 {0, 0, 0, 0, 0, 0, 0, 7, 5},
						 {0, 0, 0, 0, 0, 0, 0, 0, 0},
						 {0, 0, 0, 6, 8, 0, 3, 0, 0},
						 {1, 0, 5, 0, 7, 0, 0, 0, 0},
						 {0, 0, 0, 0, 5, 0, 0, 0, 0},
						 {0, 3, 0, 0, 0, 0, 4, 0, 0},
					 	 {8, 0, 0, 9, 0, 0, 0, 0, 0}};
    static int[][] arr4={{0, 0, 5, 3, 0, 0, 0, 0, 0},
          				 {8, 0, 0, 0, 0, 0, 0, 2, 0},
          				 {0, 7, 0, 0, 1, 0, 5, 0, 0},
          				 {4, 0, 0, 0, 0, 5, 3, 0, 0},
          				 {0, 1, 0, 0, 7, 0, 0, 0, 6},
          				 {0, 0, 3, 2, 0, 0, 0, 8, 0},
          			     {0, 6, 0, 5, 0, 0, 0, 0, 9},
          			 	 {0, 0, 4, 0, 0, 0, 0, 3, 0},
          				 {0, 0, 0, 0, 0, 9, 7, 0, 0}};
    static int[][] arr5={{0, 8, 0, 0, 0, 0, 0, 0, 0},
    					 {9, 0, 0, 5, 0, 0, 7, 0, 0},
                         {0, 0, 1, 0, 0, 4, 0, 0, 2},
                         {8, 0, 0, 0, 0, 1, 2, 0, 4},
                         {0, 0, 0, 0, 9, 0, 0, 0, 0},
                         {0, 5, 3, 7, 0, 0, 0, 9, 0},
                         {0, 6, 0, 0, 0, 2, 0, 8, 0},
                         {0, 0, 2, 1, 0, 0, 0, 0, 7},
                         {0, 0, 0, 0, 0, 0, 6, 0, 0}};
    static int[][] arr6={{9, 0, 0, 0, 0, 0, 0, 0, 0},
        				 {0, 0, 3, 6, 0, 0, 0, 0, 0},
        				 {0, 7, 0, 0, 9, 0, 2, 0, 0},
        				 {0, 5, 0, 0, 0, 7, 0, 0, 0},
        				 {0, 0, 0, 0, 4, 5, 7, 0, 0},
        				 {0, 0, 0, 1, 0, 0, 0, 3, 0},
        				 {0, 0, 1, 0, 0, 0, 0, 6, 8},
        				 {0, 0, 8, 5, 0, 0, 0, 1, 0},
        				 {0, 9, 0, 0, 0, 0, 4, 0, 0}};
    static int[][] arr=new int[9][9];
	static int count=0;	
	static long startTime;
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("请选择数独库,输入数字1-6:");
		Scanner x = new Scanner(System.in);
		int n = x.nextInt();
		startTime = System.currentTimeMillis();
		switch(n) {
		case 1:
			arr=arr1;break;
		case 2:
			arr=arr2;break;
		case 3:
			arr=arr3;break;
		case 4:
			arr=arr4;break;
		case 5:
			arr=arr5;break;
		case 6:
			arr=arr6;
		}
		show();
		for(int i=0;i<=80;i+=1) {
			if(arr[i/9][i%9]==0) {
				count+=1;
			}
		}
		dfs(0);
		System.out.println("无解!");
	}

	public static boolean logic(int y, int x, int k) {  
        for(int i=0;i<9;i+=1) {
        	if(k==arr[y][i]) {
        		return false;
        	}
        }
        for(int j=0;j<9;j+=1) {
        	if(k==arr[j][x]) {
        		return false;
        	}
        }
        int h=(y / 3) * 3 * 9 + (x / 3) * 3;
        for(int head=h;head<=h+18;head+=9) {
        	for(int j=head;j<head+3;j+=1) {
            	if(k==arr[j/9][j%9]){
            		return false;
            	}
        	}
        }
        return true;
	}

	public static void show() {
		for(int i=0;i<9;i+=1) {
			for(int j=0;j<9;j+=1) {
				System.out.print(arr[i][j]+" ");
			}
			System.out.println("");
		}
		System.out.println("");
		if(count>0) {
			long endTime = System.currentTimeMillis();    //获取结束时间
			System.out.println("程序运行时间:" + (endTime - startTime)*0.001 + "s"); 
			System.exit(0);
		}
	}
	
	public static int getvip() {
		int minn=10;
		int indexx=0;
		for(int i=0;i<=80;i+=1) {
			if(arr[i/9][i%9]==0) {
				int c=0;
				for(int av=1;av<=9;av+=1) {
					if(logic(i/9,i%9,av)) {
						c+=1;
					}
				}
				if(minn>c) {
					minn=c;
					indexx=i;
					if(minn==1) {
						return indexx;
					}
					if(minn==0) {
						return -1;
					}
				}
			}
		}
		return indexx;
	}
	
	public static void dfs(int n) {
		int m=getvip();
		if(m==-1) {
			return;
		}
		//System.out.println(vector1.size());
		for(int avail=0;avail<=9;avail+=1) {
			if(logic(m/9,m%9,avail)) {
				arr[m/9][m%9]=avail;
				if(n==count-1) {
					show();
				}
				dfs(n + 1);
				arr[m/9][m%9]=0;
			}
	    }
    }
}
请选择数独库,输入数字1-6:
2
0 0 0 0 0 2 0 5 0 
0 7 8 0 0 0 3 0 0 
0 0 0 0 0 4 0 0 0 
5 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 0 
0 0 0 0 3 0 7 0 8 
2 0 0 0 0 0 0 4 0 
0 0 0 0 0 5 0 9 0 
0 1 0 0 7 0 0 0 0 

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

程序运行时间:0.041s

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值