簡體   English   中英

拓撲排序與分組

[英]Topological Sort with Grouping

好的,所以在拓撲排序中,取決於輸入數據,通常有多個正確的解決方案,可以對圖表進行“處理”,以便所有依賴關系都在“依賴”它們的節點之前。 但是,我正在尋找一個稍微不同的答案:

假設以下數據: a -> bc -> da必須出現在bc必須來到之前d )。
只有這兩個約束我們有多個候選解決方案:( abcdacdbcabd等)。 但是,我正在尋找創建一種“分組”這些節點的方法,以便在處理組之后,下一組中的所有條目都會依賴它們的依賴關系。 對於上面假設的數據,我會尋找像(a, c) (b, d)這樣的分組。 在每個組內不要緊何種順序節點被處理( acb之前d等,並反之亦然)只是只要1組(a, c)完成前的任何組2的(b, d)正在處理中。

唯一額外的問題是每個節點應該盡可能在最早的組中。 考慮以下:
a -> b -> c
d -> e -> f
x -> y

(a, d) (b, e, x) (c, f, y)的分組方案在技術上是正確的,因為xy之前,更優化的解是(a, d, x) (b, e, y) (c, f)因為在組2中具有x意味着x依賴於組1中的某個節點。

關於如何做到這一點的任何想法?


編輯:我想我設法將一些解決方案代碼拼湊在一起。 感謝所有幫助過的人!

// Topological sort
// Accepts: 2d graph where a [0 = no edge; non-0 = edge]
// Returns: 1d array where each index is that node's group_id
vector<int> top_sort(vector< vector<int> > graph)
{
    int size = graph.size();
    vector<int> group_ids = vector<int>(size, 0);
    vector<int> node_queue;

    // Find the root nodes, add them to the queue.
    for (int i = 0; i < size; i++)
    {
        bool is_root = true;

        for (int j = 0; j < size; j++)
        {
            if (graph[j][i] != 0) { is_root = false; break; }
        }

        if (is_root) { node_queue.push_back(i); }
    }

    // Detect error case and handle if needed.
    if (node_queue.size() == 0)
    {
        cerr << "ERROR: No root nodes found in graph." << endl;
        return vector<int>(size, -1);
    }


    // Depth first search, updating each node with it's new depth.
    while (node_queue.size() > 0)
    {
        int cur_node = node_queue.back();
        node_queue.pop_back();

        // For each node connected to the current node...
        for (int i = 0; i < size; i++)
        {
            if (graph[cur_node][i] == 0) { continue; }

            // See if dependent node needs to be updated with a later group_id
            if (group_ids[cur_node] + 1 > group_ids[i])
            {
                group_ids[i] = group_ids[cur_node] + 1;
                node_queue.push_back(i);
            }
        }
    }

    return group_ids;
}

標記級別值為0的所有根節點。標記級別值為parent + 1的所有子節點。 如果正在重新訪問節點,即它已經分配了一個級別值,請檢查先前分配的值是否低於新值。 如果是這樣,請使用更高的值更新它並將它們傳播給后代。

現在,你有多個組,因為有獨特的級別標簽0 ... K.

我最近實現了這個算法。 我從你展示的方法開始,但它沒有擴展到超過2億個節點的圖形。 我最終得到的解決方案基於此處詳述的方法

您可以將其視為計算每個節點的高度,然后結果是給定高度的每個節點的一組。

考慮圖表:

A - > X.

B - > X.

X - > Y.

X - > Z.

所以期望的輸出是(A,B),(X),(Y,Z)

基本方法是找不到任何東西使用它(本例中為A,B)。 所有這些都在0高度。

現在從圖中刪除A和B,找到任何現在沒有使用它的東西(在這個例子中現在是X)。 所以X的高度為1。

從圖中刪除X,找到任何現在沒有使用它的東西(在本例中為Y,Z)。 所以Y,Z的高度為2。

您可以通過實現以下事實進行優化:您不需要為所有內容存儲雙向邊緣或實際從圖形中刪除任何內容,您只需要知道指向節點的事物數量以及您知道的節點數量。下一個高度。

所以對於這個例子的開頭:

  • 0件事使用1
  • 0件事使用2
  • 2件事使用X(1和2)
  • 1件事使用Y,Z(X)

當您訪問節點時,減少它指向的每個節點的數量,如果該數字變為零,則您知道該節點處於下一個高度。

暫無
暫無

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

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