深度优先算法(dfs)
概念:进行某种数据查找时,使用堆栈+递归的方式对当前节点的每一种可能性进行逐个尝试,如果当前节点是末端节点且包含满足的条件,则逐层返回成功结束,如果当前节点满足条件,并且还有下挂节点时,则根据下挂节点执行的情况判断当前节点数据是否合适,如果当前节点没有满足条件则需要回退当前节点修改的信息,并返回失败,让上一个节点执行其余场景。
举例:有一个全二叉树,每一个节点都有一个value,请获取一条和为10的分支,全二叉树如下图所示:
如果使用深度优先的搜索方式,逻辑大概如下;
a.开始节点时node1,vaule是5,我们优先选择左侧子树进行遍历
b.现在的节点是(node1-node2),value是8,此时还不是末端节点,我们选择node2的左侧子树
c.现在的节点是(node1-node2-node4),value是14,此时node4是末端节点,但是value不等于10,因此需要将node4移除,现在的节点是(node1-node2),value是8,此时选择node2的右侧子树
d.现在的节点是(node1-node2-node5),vaule是9,此时node5是末端节点,但是value不等于10,因此需要将node5移除,现在的节点是(node1-node2),value是8.
e.因为node2下的所有节点都不满足要求,因此需要将node2移除,现在的节点是(node1),value5,此时选择node1的右侧子树
f.现在的节点是(node1-node3),vaule是7,此时还不是末端节点,我们选择node3左侧的子树
g.现在的节点是(node1-node3-node6),vaule是10,因为node6是叶子节点,并且value是10已经满足要求,此时直接结束
题:给出一个9*9的数独,请使用深度优先搜索的方式计算出位置位置的数字(未知数字用0表示)
package com.anran.example.test;
import java.util.*;
/**
* 数独
*
* 样例1
* 输入:
* 9 1 0 0 7 4 0 0 0
* 0 0 0 6 0 0 2 4 0
* 4 0 2 0 0 0 0 0 6
* 0 0 0 5 0 0 0 3 0
* 2 4 8 0 0 0 1 0 5
* 7 0 0 8 4 0 0 6 0
* 0 0 3 0 8 2 0 0 1
* 1 0 0 0 0 5 8 0 0
* 0 2 4 0 6 0 3 0 0
*
* 输出:
* 9 1 6 2 7 4 5 8 3
* 3 5 7 6 1 8 2 4 9
* 4 8 2 9 5 3 7 1 6
* 6 9 1 5 2 7 4 3 8
* 2 4 8 3 9 6 1 7 5
* 7 3 5 8 4 1 9 6 2
* 5 7 3 4 8 2 6 9 1
* 1 6 9 7 3 5 8 2 4
* 8 2 4 1 6 9 3 5 7
*
* 样例2
* 输入:
* 5 3 9 1 0 0 0 0 0
* 0 0 0 9 0 5 0 6 0
* 8 0 0 4 0 0 0 9 1
* 0 5 0 0 8 0 2 4 0
* 0 0 6 0 3 0 8 0 0
* 0 0 8 2 0 0 6 0 0
* 9 0 0 0 4 7 0 0 0
* 0 0 0 0 0 2 0 3 7
* 3 4 0 0 0 0 0 0 2
*
* 输出:
* 5 3 9 1 6 8 7 2 4
* 1 7 4 9 2 5 3 6 8
* 8 6 2 4 7 3 5 9 1
* 7 5 3 6 8 1 2 4 9
* 2 9 6 7 3 4 8 1 5
* 4 1 8 2 5 9 6 7 3
* 9 2 5 3 4 7 1 8 6
* 6 8 1 5 9 2 4 3 7
* 3 4 7 8 1 6 9 5 2
*/
public class Main5 {
//逻辑:从前往后每一个节点如果不确定,每一种场景都进行匹配操作,如果后续节点出现无法满足要去的数据,则回到上一个节点,执行
// 其余场景,如果满足要求则直接结束
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
// 每一个while处理一下9*9的数据
while(sc.hasNext()){
//存放所有数据
int[][] datas = new int[9][9];
// 输入
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
datas[i][j] = sc.nextInt();
}
}
if (dfs(0, 0, datas)) {
// 输出
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(datas[i][j] + " ");
}
System.out.println("");
}
} else {
System.out.println("Error");
}
}
sc.close();
}
private static boolean dfs(int line, int row, int[][] datas) {
if (line == 9 && row == 0) {
return true;
}
if (datas[line][row] != 0) {
// 已经明确的信息,直接跳过
return dfs(getNextLine(line, row), getNextRow(row), datas);
} else {
for (int i = 1; i <= 9; i++) {
// 判断行、列、3*3单元格是否包含这个数字
if (checkNum(i, line, row, datas)) {
// 当前数字未使用,添加到datas中
datas[line][row] = i;
//使用递归计算后面的
if (dfs(getNextLine(line, row), getNextRow(row), datas)) {
// 如果后面的满足要求,则直接结束
return true;
}
// 如果没有结束,当前节点需要还原成原始信息
datas[line][row] = 0;
}
}
return false;
}
}
private static boolean checkNum(int currentNum, int line, int row, int[][] datas) {
// 判断行和列中是否包含数字
for (int i = 0; i < 9; i++) {
if (currentNum == datas[line][i] || currentNum == datas[i][row]) {
return false;
}
}
// 判断3*3单元格中是否包含数字
for (int i = line/3*3; i < line/3*3+3; i++) {
for (int j = row/3*3; j < row/3*3+3; j++){
if (currentNum == datas[i][j]) {
return false;
}
}
}
return true;
}
private static int getNextLine(int line, int row) {
return row == 8 ? line + 1 : line;
}
private static int getNextRow(int row) {
return row == 8 ? 0 : row + 1;
}
}
未完待续 。。。