[英]Longest Path for Directed Cyclic Graph
使用哪種算法通過有向循環未加權圖找到最長路徑。 每個節點僅指向另一個節點。 這些圖最多包含10 ^ 9個節點。 (我在這里搜索,谷歌搜索都無濟於事。)
請參閱烏龜和野兔回路檢測 -您發送一個迭代器,其步長為1(烏龜),另一個發送迭代器,其步長為2(野兔)。 如果列表中有一個循環,它們必然會相遇。 ( 另外一個關於SO的問題 )。
一旦烏龜遇到了野兔,
一旦野兔踩到了已經被烏龜訪問過的節點上(即它們都在一個環內),就停止野兔,將烏龜帶到與野兔相同的位置,然后讓烏龜繞環繞行再次計算循環的長度 (以檢查到目前為止的最大值)
采取另一個尚未訪問的節點,然后轉到步驟2
C ++解決方案
size_t maxLoopLen(const std::vector<size_t>& nextNodeIndexes) {
size_t len=nextNodeIndexes.size();
std::vector<bool> visitTrace(len, false);
size_t ret=0; // the max number of elements in the loop
for(;;) {
// find the first non-visited node
size_t pos=0;
for(pos=0; pos<len && visitTrace[pos]; pos++);
if(pos>=len) { // no more unvisited nodes
break;
}
// this is needed for the "ring with string attached" topology
// The global visitTrace contains the exploration of the prev
// loos or **string leading to the same loop** - if the hare
// steps on one of those prev strings, it may stop prematurely
// (on the string, not inside the loop)
std::vector<bool> currCycleTrace(len, false);
size_t hare=pos, tortoise=pos;
bool hareOnKnownPosition=false;
while ( !currCycleTrace[hare] && !hareOnKnownPosition) {
if(visitTrace[hare]) {
// the hare just got to revisit something visited on prev cycles
// *** ***********************************************************
// *** this is where the algo achieves sub-O(N^2) time complexity
// *** ***********************************************************
hareOnKnownPosition=true;
break;
}
// mark the tortoise pos as visited
visitTrace[tortoise]=currCycleTrace[tortoise]=true;
// tortoise steps with increment of one
tortoise=nextNodeIndexes[tortoise];
// hare steps two
hare=nextNodeIndexes[hare];
hare=nextNodeIndexes[hare];
}
// we got out of that cycle because the hare stepped on either:
// - a tortoise-visited place on the current cycle - in this case
// both the tortoise and the hare are inside a not-yet-explored
// loop.
// - on a place where the tortoise has been when it discovered a
// loop at prev cycles (think "ring with multiple string attached"
if(!hareOnKnownPosition) {
// The hare stepped on a new loop, not a loop visited before
// Bring the tortoise to the same position as the hare. keep the
// hare still and start counting how many steps until the tortoise
// gets back to the same place
tortoise=hare;
size_t currLoopElemCount=0;
do {
tortoise=nextNodeIndexes[tortoise];
currLoopElemCount++;
} while(tortoise!=hare);
ret=std::max(currLoopElemCount, ret);
}
}
return ret;
}
#include <iostream>
int main() {
std::vector<size_t> lasso={3,3,1,2,0};
// expected 3, with cycle at nodes at indexes 1,2,3
std::cout << "lasso max loop len " << maxLoopLen(lasso) << std::endl;
// expected 2. The ring index 1 and 2. Two connected strings
// - starting at index 0 - 0->3->2 and we are inside the ring
// - starting at index 4 - 4->1 and we are inside the ring
std::vector<size_t> ringWith2Strings={3,2,1,2,1};
std::cout << "ringWith2Strings max loop len "
<< maxLoopLen(ringWith2Strings) << std::endl;
std::vector<size_t> singleElem={0};
std::cout << "singleElem max loop len " << maxLoopLen(singleElem) << std::endl;
std::vector<size_t> allTogether={
3,3,1,2,0, // lasso
8,7,6,7,6, // ringWith2Strings shifted up 5 pos
10 // single element pointing to itself
};
std::cout << "allTogether max loop len " << maxLoopLen(allTogether) << std::endl;
}
探索“節點”的示例
lasso={3,3,1,2,0};
因此,您沒有一個圖,而是有一系列不同的圖,每個圖形成一個具有不同數量節點的閉合鏈。
在這種情況下,您可以實現一種算法,該算法大致使用O(n)
時間復雜度和O(n)
空間復雜度(假設對所有節點的隨機訪問,並且每個節點的ID都遞增)。
從第一個節點開始,並遍歷鏈,直到您回到第一個節點。 對於每個訪問的節點,請使用鏈標識符對其進行標記。 存儲此鏈ID的訪問節點數。 然后,轉到下一個節點(按ID,不在鏈中),檢查它是否已被標記為鏈的一部分。 如果是,請繼續; 如果沒有,請處理鏈條。 這樣做,直到找到最后一個節點ID。 至此,您已經知道了所有鏈的長度,然后選擇了最長的鏈。
首先以遞歸方式刪除度內零的每個頂點(在O(n)中)。 結果圖只是循環的不相交的並集。
取得任意節點,運行dfs,並找到其所屬循環的長度(僅通過訪問鄰居即可,這是自然的dfs)。 對每個未訪問的節點繼續執行此操作。 最后,您可以輸出最大的循環。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.