数独 - 暴力深搜

207 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

数独是根据 9×9 盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫内的数字均含 1−9 ,不重复。每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的。

来源:洛谷 www.luogu.com.cn/problem/P17…

输入格式

一个未填的数独。

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

输出格式

填好的数独。

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

二、思路分析:

这是一道搜索题,填数字的条件是每一行、每一列、每一个粗线宫内的数字均含 1−9 ,不重复。 满足每一行、每一列不重复很简单,但是我们如何表示在每一个粗线宫内不重复呢?

根据例题我们可以看到 3*3 的小格为一个粗线宫, 9×9 的盘面上一共有 9 个粗线宫

image.png 我们可以通过该位置的行和列来判断它属于哪一个粗线宫, i/3*3 + j/3 因为每行3个嘛~ , 例如(0,0)它就属于第0个粗线宫, (8,8)就属于第8个粗线宫

我们从 (0,0)位置开始填数,一直往下走 (0,1)、(0,2).....(0,8)、(1,0)、(1,1)....... 当能判断到(9,0)的时候,说明我们已经找到答案了,由于仅有唯一答案,我们找到后直接返回即可。 如果该位置本来就有数字的话,直接往下走去填下一个位置的数,若该位置需要填数字,我们需要对它进行判断,并进行标记和回溯

三、AC 代码:

import java.util.*;

public class Main {
	static int[][] map;
	static boolean[][] hen, shu, gezi;

	public static void main(String[] args) {

		Scanner sr = new Scanner(System.in);
           // 地图 (将输入为0的位置改变成 1-9 后输出)
		map = new int[10][10];
		hen = new boolean[10][10];   // 横
		shu = new boolean[10][10];   // 竖
		gezi = new boolean[10][10];  // 粗线宫
		for (int i = 0; i < 9; i++)
			for (int j = 0; j < 9; j++) {
				map[i][j] = sr.nextInt();
                     // 当这个位置本来就有数字,需要对它进行标注
				if (map[i][j] != 0) {
					hen[i][map[i][j]] = true;
					shu[j][map[i][j]] = true;
					gezi[i / 3 * 3 + j / 3][map[i][j]] = true;
				}
			}
           // 从(0, 0)开始
		fun(0, 0);
	}

	private static void fun(int x, int y) {
		if (x == 9) // 输出
		{
			for (int i = 0; i < 9; i++) {
				for (int j = 0; j < 9; j++)
					System.out.print(map[i][j] + " ");
				System.out.println();
			}
			return;
		}
           // 换下一行
		if (y == 9)
			fun(x + 1, 0);
           // 本来就有数字
		if (map[x][y] != 0) {
			fun(x, y + 1);
		} else {
                // 1-9 的数字都试一下能不能填在这个位置
			for (int k = 1; k <= 9; k++)
				if (!hen[x][k] && !shu[y][k] && !gezi[x / 3 * 3 + y / 3][k]) {
                                        // 标记并回溯
					map[x][y] = k;
					hen[x][k] = true;
					shu[y][k] = true;
					gezi[x / 3 * 3 + y / 3][k] = true;
					fun(x, y + 1);
					hen[x][k] = false;
					shu[y][k] = false;
					gezi[x / 3 * 3 + y / 3][k] = false;
					map[x][y] = 0;
				}
		}
	}
}

四、总结:

一整个就是一个暴力深搜的大动作😃 主要就是在如何判断这个数字能不能填在该粗线宫内不重复,这里想清楚了,就很简单了,八皇后的案例和这个挺像的