Java数独算法(原创)

13 篇文章 0 订阅
8 篇文章 0 订阅
import java.util.Scanner;

public class Shudu_sy {

	// shanshan是存储上次
	static int[] shanshan = new int[81];
	static int[][] num_aa = new int[9][9];
	static int[][] num_bb = new int[9][9];
	static int[] num_all = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	public static void main(String[] args) {
		scan_num(); // 输入数组
		change_shan();// 初始化我们的统计数组shanshan
		change(0, 0); // 这个0,0 (这里不是表情)是对应数组的第0行0列,这个功能主要是方便大家可以在这个代码的基础上修改
	}

	// 初始化该计数数组
	public static void change_shan() {
		for (int i = 0; i < shanshan.length; i++) {
			shanshan[i] = 0;
		}
	}

	// 这里面的shanshan数组是用来记录上次该为存储的是第几个数据,shanshan的下边对应该9*9数组中
	// 的行x*9+列y,即x*9+y

	// 采用递归调用,如果失败则返回上一步
	public static void change(int x, int y) {
		int yy = y; // 这里的yy是因为我采用递归调用,改变这个双层for循环的i和j的值
		a: for (int i = 0; i < 9; i++) {
			// 标签a也是为了返回上一步的跳转做准备的
			for (int j = yy; j < 9; j++) {
				if (j == 8) {
					yy = 0;
				}
				// yy默认为0,跳转后指定位置后j每次开始的位置会发生改变,所以我选择把他手动置0(从0开始)
				if (num_bb[i][j] == 0) {
					// num_bb是备份数组,用来测试这个位置是否本来是空
					int num = sy(i, j, i * 9 + j);
					if (num != -1) {// 有正确数据的时候
						num_aa[i][j] = num;// 我们在该位置填充该数据(num_aa中更新数据)
					} else if (num == -1) {// 如果没有正确数据,我们执行返回上一步操作
						String[] aa = sys(num_bb, i, j).split(",");
						i = Integer.parseInt(aa[0]) - 1;// 对应i的位置,但是因为i++,所以我们提前先-1
						yy = Integer.parseInt(aa[1]);// 直接对应j的位置,不需要-1
						continue a;
					}
				}
			}
		}
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				System.out.print(num_aa[i][j] + ",");
			}
			System.out.println();
		}
		// 如果该数独已经计算完毕,我们把该数独输出出来,大家也可以把这个输出给美化一下
	}

	// 清空错误数据的缓存
	// 当然这一步和这一步后num_aa中的数据和shanshan中的缓存必须要被清空
	public static void clean(int x, int y) {
		int num = x * 9 + y;
		for (int i = num; i < 81; i++) {
			shanshan[i] = 0;
		}
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (i * 9 + j >= num) {
					num_aa[i][j] = num_bb[i][j];
				}
			}
		}
	}

	// 进行返回上一步操作,同时把这一步后面的shanshan里的数据清空。
	public static String sys(int[][] aa, int x, int y) {
		clean(x, y);
		for (int i = 8; i >= 0; i--) {
			for (int j = 8; j >= 0; j--) {
				if (num_bb[i][j] != num_aa[i][j] && i * 9 + j < x * 9 + y) {
					return i + "," + j;
				}
			}
		}
		return null;
		// 再清空数据之后,我们获得上一个num_bb中为0的数据的位置,以i,j的形式返回
	}

	// 输出一个可能是正确的答案,如果不存在则输出-1,同时更新shanshan里面的数据
	public static int sy(int x, int y, int a) {
		if (shanshan[a] == 9) {
			return -1;
		}// 如果该位置的缓存为9,表明该位置没有正确数据
		for (int i = shanshan[a]; i < 9; i++) {// 从上一次正确位置之后开始
			if (testOne(num_all[i], x, y) == 0) { // 如果有一个正确的数据,即返回0的时候
				shanshan[a] = num_all[i];// 我们先把缓存更新
				return num_all[i];// 同时返回这个正确的数据
			}
		}
		return -1; // 如果没有正确的数据我们就返回-1
	}

	// 这个sy函数是对该位置进行测试,看该位置是否存在一个正确的数据

	// 传入要测试的数据,和该数据所在的行和列,看是否存在数据重复,无冲突输出0,有冲突输出-1
	public static int testOne(int num, int x, int y) {

		// 检测该行该列是否有重复数字出现
		for (int i = 0; i < 9; i++) {
			if (num_aa[x][i] == num || num_aa[i][y] == num) {
				return -1;
			}
		}
		// num_aa是我们用来修改的数据数组

		// 检测3*3的正方块中是否有重复数字出现
		for (int i = x / 3 * 3; i < x / 3 * 3 + 3; i++) {
			for (int j = y / 3 * 3; j < y / 3 * 3 + 3; j++) {
				if (i == x && j == y) {
					break;
					// 如果是该空格自身则不用比较
				} else if (num_aa[i][j] == num) {
					return -1;
					// 如果该方格已存在该数据则返回-1
				}
			}
		}
		// 这里x/3*3,y/3*3后会自定确定该该数据所对应的3*3小方格的左上角那个数据,然后再对该数据i和j进行++操作

		return 0;
		// 如果该方格不存在这个数据则返回0
	}

	// 输入该9*9九宫格,用英文下的逗号隔开,如果为空则输入0
	public static void scan_num() {
		System.out.println("please input information");// 提示代码
		Scanner scanner = new Scanner(System.in);
		for (int i = 0; i < 9; i++) {
			String a[] = scanner.nextLine().split(",");
			for (int j = 0; j < a.length; j++) {
				num_aa[i][j] = Integer.parseInt(a[j]);
				num_bb[i][j] = Integer.parseInt(a[j]);
				// 这里采用两个相同的数组,是因为等会要对第一个数组num_aa进行操作,操作的时候和数组num_bb进行对比,来区分
				// 这个方格对应的数字是后来自己写的,还是原本系统就有的
			}
		}

		// 直接两个for循环输入
		scanner.close();
		System.out.println("input end");
	}

	// 这是一段简单的输入程序
}


这个小程序采用的简单的模块处理机制,没事写着玩玩。




  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值