我无法解决这个问题。我必须从有向图中包含简单循环的源顶点 s 开始找到所有简单路径。即,不允许重复,当然除了循环连接回路径的单个重复顶点。
我知道如何使用DFS访问来查找图表是否有周期,但我无法找到一种方法来使用它来查找从 s 开始的所有此类路径。
例如,在此图中
+->B-+
| v
s-->T-->A<---C
| ^
+->D-+
从s
开始,将正确找到路径S-T-A-B-C-A。但是找不到路径S-T-A-D-C-A,因为顶点C被标记为DFS访问。
有人可以提示我如何解决这个问题吗? 感谢
答案 0 :(得分:6)
这实际上是一个非常简单的算法,比DFS简单。您只需在一个简单的递归搜索中枚举所有路径,记住在路径循环回来的任何时候都不再递归:
(这只是一个Python启发的伪代码。我希望它足够清楚。)
def find_paths_with_cycles(path_so_far):
node_just_added = path_so_far.back()
for neigh in out_neighbours(node_just_added):
if neigh in path_so_far:
# this is a cycle, just print it
print path_so_far + [neigh]
else:
find_paths_with_cycles(path_so_far + [neigh])
initial_path = list()
initial_path.append(s)
find_paths_with_cycles(initial_path)
答案 1 :(得分:0)
这是垃圾收集算法的常见问题。
在.net培训中,我了解到.net垃圾收集器通过从图中的两个指针开始检测周期,其中一个指针的速度是另一个指针的两倍。如果快速前进的一个从后面进入慢速,你发现了一个循环。它将更复杂地用于复杂的图形,但它可以在不标记节点的情况下工作。
答案 2 :(得分:0)
当您找到一个循环时,返回并在缩回过去时取消标记顶点。
假设您找到了SABCA并希望找到下一个周期。 A是您的最终节点,您不应该取消标记。回到C. C还有另一个优势吗?不,所以取消标记C 并返回B.是否还有另一条边缘走出B?不,取消标记B并返回A.是否有另一个边缘走出A?是!有一个去D.所以去那里,标记D,去C 现在没有标记,然后到A.在这里,你找到了另一个循环。你再次缩回A,但现在没有更多的路径从A出来,所以你取消标记A并返回S。
答案 3 :(得分:0)
我继续用C#实现了Aaron的算法。
因为它使用延迟枚举的IEnumerable,你可以使用DirectedGraphHelper.FindSimpleCycles(s).First()如果你只想要找到第一个循环:
public static class DirectedGraphHelper
{
public static IEnumerable<Node[]> FindSimpleCycles(Node startNode)
{
return FindSimpleCyclesCore(new Stack<Node>(new[] { startNode }));
}
private static IEnumerable<Node[]> FindSimpleCyclesCore(Stack<Node> pathSoFar)
{
var nodeJustAdded = pathSoFar.Peek();
foreach (var target in nodeJustAdded.Targets)
{
if (pathSoFar.Contains(target))
{
yield return pathSoFar.Reverse().Concat(new[] { target }).ToArray();
}
else
{
pathSoFar.Push(target);
foreach (var simpleCycle in FindSimpleCyclesCore(pathSoFar))
{
yield return simpleCycle;
}
pathSoFar.Pop();
}
}
}
}
public class Node
{
public string Id { get; private set; }
public readonly List<Node> Targets = new List<Node>();
public Node(string id)
{
this.Id = id;
}
}
你会像这样使用它:
class Program
{
static void Main(string[] args)
{
var s = new Node("s");
var t = new Node("t");
var a = new Node("a");
var b = new Node("b");
var c = new Node("c");
var d = new Node("d");
s.Targets.Add(t);
t.Targets.Add(a);
a.Targets.AddRange(new[] { b, d });
b.Targets.Add(c);
c.Targets.Add(a);
d.Targets.Add(c);
foreach (var cycle in DirectedGraphHelper.FindSimpleCycles(s))
{
Console.WriteLine(string.Join(",", cycle.Select(n => n.Id)));
}
Console.Read();
}
}