一道經典DFS題(深度優先)-演算法程式設計實踐

jamesehng發表於2016-12-13

DFS定義

DFS(Depth-First-Search)深度優先搜尋演算法,是搜尋演算法的一種。是一種在開發爬蟲早期使用較多的方法。它的目的是要達到被搜尋結構的葉結點 。

特點

每次深度優先搜尋的結果必然是圖的一個連通分量。深度優先搜尋可以從多點發起。如果將每個節點在深度優先搜尋過程中的“結束時間”排序(具體做法是建立一個list,然後在每個節點的相鄰節點都已被訪問的情況下,將該節點加入list結尾,然後逆轉整個連結串列),則我們可以得到所謂的“拓撲排序”,即topological sort.

當然,當人們剛剛掌握深度優先搜尋的時候常常用它來走迷宮。事實上我們還有別的方法,那就是廣度優先搜尋 (BFS)。狀態(state):狀態是指問題求解過程中每一步的狀況。

經典演算法過程

圖的深度遍歷原則:

1 如果有可能,訪問一個領接的未訪問的節點,標記它,並把它放入棧中。

2 當不能執行規則 1 時,如果棧不為空,則從棧中彈出一個元素。

3 如果不能執行規則 1 和規則 2 時,則完成了遍歷。

典型例項(兵臨城下)

該題目是樂視的面試程式設計題

盧卡斯的驅逐者大軍已經來到了赫柏的卡諾薩城,赫柏終於下定決心,集結了大軍,與驅逐者全面開戰。 盧卡斯的手下有6名天之驅逐者,這6名天之驅逐者各賦異能,是盧卡斯的主力。 為了擊敗盧卡斯,赫柏必須好好考慮如何安排自己的狂戰士前去迎戰。 狂戰士的魔法與一些天之驅逐者的魔法屬性是相剋的,第i名狂戰士的魔法可以剋制的天之驅逐者的集合為Si(Si中的每個元素屬於[0,5])。 為了公平,兩名狂戰士不能攻擊同一個天之驅逐者。 現在赫柏需要知道共有多少種分派方案。 例: S1={01},S2={23},代表編號為0的狂戰士的魔法可以剋制編號為0和編號為1的天之驅逐者,編號為1的狂戰士的魔法可以剋制編號為2和編號為3的天之驅逐者,共有四種方案:02,03,12,13。 02---代表第一個狂戰士負責編號為0的驅逐者,第二個狂戰士負責編號為2的驅逐者; 03---代表第一個狂戰士負責編號為0的驅逐者,第二個狂戰士負責編號為3的驅逐者; 12---代表第一個狂戰士負責編號為1的驅逐者,第二個狂戰士負責編號為2的驅逐者; 13---代表第一個狂戰士負責編號為1的驅逐者,第二個狂戰士負責編號為3的驅逐者; S1={01},S2={01},代表編號為0的狂戰士的魔法可以剋制編號為0和編號為1的天之驅逐者,編號為1的狂戰士的魔法可以剋制編號為0和編號為1的天之驅逐者,共有兩種方案:01,10。

輸入描述:

多組測試資料,請處理到檔案結束。

對於每組測試資料:

第一行為一個整數N,代表狂戰士的數量。

第二行為N個字串,第i個字串表示第i個狂戰士能夠剋制的天之驅逐者的集合。

保證:

1<=N<=6,1<=每個字串的長度<=6,且每個字元都是0~5中的一個數字。

輸出描述:

輸出一個整數,代表分配方案數

輸入例子:

2 01 23 2 01 01 3 3 015 5

輸出例子:

4 2 2

分析:

1.對於這種遍歷的問題,考慮採用經典的DFS,設定一個輔助的陣列(題目要求不能兩個人打一個),來記錄是否是否是唯一的。

2.判斷每個分支的截止條件,通過遞迴和迴圈完成遍歷。

程式碼:

public class Main {
     
    private static int ans;
     
    public static int getAns(String[] str, int n) {
        ans = 0;
        int[] vis = {0, 0, 0, 0, 0, 0};
        dfs(str, vis, n, 0);
        return ans;
    }
     
    public static void dfs(String[] str, int[] vis, int n, int p) {
        if (p == n) {
            ans++;
            return ;
        }
        for (int i = 0; i < str[p].length(); i++) {
            if (vis[str[p].charAt(i) - '0'] == 0) {
                vis[str[p].charAt(i) - '0'] = 1;
                dfs(str, vis, n, p + 1);
                vis[str[p].charAt(i) - '0'] = 0;
            }
        }
    }
     
    public static void main(String[] args) {
        Scanner in = new Scanner(new BufferedInputStream(System.in));
        while (in.hasNext()) {
            int n = in.nextInt();
            String[] str = new String[n];
            for (int i = 0; i < n; i++) {
                str[i] = in.next();
            }
             
            int ans = getAns(str, n);
            System.out.println(ans);
        }
        in.close();
    }
         
}
複製程式碼

相關文章