簡體   English   中英

如何在樹上執行DFS? (不一定是二進制)

[英]How to do a DFS on a tree? (not necessarily binary)

我有一棵n節點的樹(標記為0 to n )。 我使用兩個向量來保存邊緣信息。

typedef std::vector<std::vector<int>> graph;

輸入形式為n-1邊:

0 1
1 2
2 3
and so on 

有人告訴我節點0始終是根節點。 我使用以下方法掃描邊緣:

for (int i = 0; i < n-1; i++) {
    scanf("%d %d", &a, &b);
    g[a].push_back(b);
    g[b].push_back(a); // the second approach doesn't use this line
}

這是我簡單的dfs:

void dfs(graph &g, int v) {
    std::vector<int> visited; // I don't use a visited array for the second approach
    for (int i = 0; i < g.size(); i++) {
        visited.push_back(0);
    }
    std::stack<int> s;
    std::set<int> t;
    s.push(v);
    while (!s.empty()) {
        int i = s.top(); s.pop();
        // do stuff
        for (int i = 0; i < g[v].size(); i++) {
            if (!visited[i]) {
                visited[i] = true;
                s.push(g[v][i]);
            }
        }
    }
}

例如,說我們有4個節點和以下邊:

0 1
0 2
3 2
2 4

假設我對從2開始的子樹感興趣。 上面的方法行不通,因為我要插入無方向的邊0 22 0 因此,當我從2開始dfs ,將節點0添加到堆棧中是錯誤的。

我嘗試了另一種方法,即僅插入給定的邊,但是也沒有用,因為在示例中,我將插入3 2 ,這是從3到節點2的邊,因此當我在節點2啟動dfs ,我贏了無法到達節點3

我覺得問題很簡單,而且我缺少一些大創意!

由於您的圖是一棵有根的樹,因此可以進行以下預處理。

  1. 從根目錄啟動DFS(頂點#0);
  2. 對於每個頂點u ,存儲其父 v 這意味着,如果沿着從根到u的最短路徑行進,則該路徑上倒數第二個頂點將是v 請注意,在任何一棵樹中,從一個頂點到另一個頂點都只有一條最短的路徑。 假設您有一個數組parent ,根據上述定義, parent[u] = v ,並且parent[0] = -1
    您可以通過注意計算parent數組,如果您執行s.push(g[v][i]) ,則vi的父級(否則您將首先訪問i );
  3. 由於parent[v]是距全局根(vertex 0)最短路徑的先前頂點,因此它也是距其子樹中包含v的任何頂點x的最短路徑的先前頂點。

現在,當您想在頂點u的子樹上進行DFS時,您可以像現在那樣執行DFS,但不要訪問任何頂點的父級 說,如果要執行s.push(v) ,而parent[u] = v ,則不要這樣做。 這樣,您將永遠不會離開u的子樹。

實際上,了解parent ,您可以擺脫visited數組。 當您對頂點v進行 “處理”時,已經訪問過的v的唯一鄰居是parent[v] 此屬性不依賴於您要遍歷其子樹的初始頂點。 DFS代碼如下所示(假設您已經完成了獲取parent預處理:

  void dfs(graph &g, vector<int> &parent, int v) {
    std::stack<int> s;
    s.push(v);
    while (!s.empty()) {
        int v = s.top(); s.pop(); // By the way, you have mistake here: int i = s.top().
        // do stuff
        for (int i = 0; i < g[v].size(); i++) {
            if (parent[v] != g[v][i]) {
                s.push(g[v][i]);
            }
        }
    }
  }

PS這種方法在某種程度上類似於您的第二種方法:它僅處理從根到子樹的邊緣。 但這沒有缺陷,例如在您的示例中“ 3 2”是錯誤的方向,因為您是通過從根目錄執行DFS從算法上推斷方向的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM