算法-深度优先搜索(dfs)

深度优先算法(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;
    }
}

 

 

未完待续 。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值