使用什么算法通过有向循环未加权图找到最长路径。每个节点仅指向另一个节点。这些图表最多有10 ^ 9个节点。 (我在这里搜索并谷歌无济于事。)
答案 0 :(得分:0)
参见the tortoise and hare loop detection - 你发送一个步长为1(乌龟)的迭代器和另一个步长为2(野兔)的迭代器。如果列表有一个循环,它们必然会遇到。 (也在another question on 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};
答案 1 :(得分:-1)
所以你没有一个单独的图,而是一系列不同的图,每个图形成一个具有不同数量节点的闭链。
如果是这种情况,您可以实现一种大致使用O(n)
时间复杂度和O(n)
空间复杂度的算法(假设随机访问所有节点,并且每个节点都有一个升序ID)。 / p>
从第一个节点开始,遍历链,直到回到第一个节点。对于每个访问节点,使用链标识符对其进行标记。存储此链ID的访问节点数。然后转到下一个节点(按ID,不在链中),检查它是否已被标记为链的一部分。如果是,请继续;如果没有,处理链。在您使用最后一个节点ID之前,请执行此操作。此时你已经完成了,你知道所有链的长度,然后你选择最长的链。
答案 2 :(得分:-1)
首先递归地移除度为零的每个顶点(在O(n)中)。结果图只是一个不相交的循环联合。
获取任意节点,运行dfs,并找到它所属的循环的长度(仅通过访问邻居,一个自然的dfs)。对每个未访问的节点继续此操作。最后,您可以输出最大的周期。