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

 

 

未完待續 。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章