如何快速找到一系列边缘中的所有路径?

时间:2012-06-16 14:58:07

标签: algorithm graph graph-algorithm minimum-spanning-tree

设E是给定的有向边集。假设已知E中的边可以形成有向树T,所有节点(根节点除外)只有1个度。问题是如何有效地遍历边集E,以便找到T中的所有路径?

例如,给定有向边集E = {(1,2),(1,5),(5,6),(1,4),(2,3)}。我们知道这样的集合E可以生成只有1度(有根节点)的有向树T.是否有任何快速方法来遍历边集E,以便按如下方式找到所有路径:

Path1 = {(1,2),(2,3)}
Path2 = {(1,4)}
Path3 = {(1,5),(5,6)}

顺便说一下,假设E中的边数是| E |,是否有找到所有路径的复杂性?

3 个答案:

答案 0 :(得分:2)

我之前没有处理过这类问题。所以只试了一个简单的解决方案。看看这个。

public class PathFinder
{
    private static Dictionary<string, Path> pathsDictionary = new Dictionary<string, Path>();
    private static List<Path> newPaths = new List<Path>();
    public static Dictionary<string, Path> GetBestPaths(List<Edge> edgesInTree)
    {
        foreach (var e in edgesInTree)
        {
            SetNewPathsToAdd(e);
            UpdatePaths();
        }
        return pathsDictionary;
    }        
    private static void SetNewPathsToAdd(Edge currentEdge) 
    {
        newPaths.Clear();
        newPaths.Add(new Path(new List<Edge> { currentEdge })); 
        if (!pathsDictionary.ContainsKey(currentEdge.PathKey()))
        {
            var pathKeys = pathsDictionary.Keys.Where(c => c.Split(",".ToCharArray())[1] == currentEdge.StartPoint.ToString()).ToList();
            pathKeys.ForEach(key => { var newPath = new Path(pathsDictionary[key].ConnectedEdges); newPath.ConnectedEdges.Add(currentEdge); newPaths.Add(newPath); });             
            pathKeys =  pathsDictionary.Keys.Where(c => c.Split(",".ToCharArray())[0] == currentEdge.EndPoint.ToString()).ToList();
            pathKeys.ForEach(key => { var newPath = new Path(pathsDictionary[key].ConnectedEdges); newPath.ConnectedEdges.Insert(0, currentEdge); newPaths.Add(newPath); });
        }            
    }
    private static void UpdatePaths()
    {
        Path oldPath = null;
        foreach (Path newPath in newPaths)
        {
            if (!pathsDictionary.ContainsKey(newPath.PathKey()))
                pathsDictionary.Add(newPath.PathKey(), newPath);
            else
            {
                oldPath = pathsDictionary[newPath.PathKey()];
                if (newPath.PathWeights < oldPath.PathWeights)
                    pathsDictionary[newPath.PathKey()] = newPath;
            }
        }
    }        
}

public static class Extensions
{
    public static bool IsNullOrEmpty(this IEnumerable<object> collection) { return collection == null || collection.Count() > 0; }
    public static string PathKey(this ILine line) { return string.Format("{0},{1}", line.StartPoint, line.EndPoint); }
}
public interface ILine 
{
    int StartPoint { get; }
    int EndPoint { get; }
}
public class Edge :ILine 
{
    public int StartPoint { get; set; }
    public int EndPoint { get; set; }

    public Edge(int startPoint, int endPoint)
    {
        this.EndPoint = endPoint;
        this.StartPoint = startPoint;
    }
}
public class Path :ILine
{
    private List<Edge> connectedEdges = new List<Edge>();
    public Path(List<Edge> edges) { this.connectedEdges = edges; }
    public int StartPoint { get { return this.IsValid ? this.connectedEdges.First().StartPoint : 0; } }
    public int EndPoint { get { return this.IsValid ? this.connectedEdges.Last().EndPoint : 0; } }
    public bool IsValid { get { return this.EdgeCount > 0; } }
    public int EdgeCount { get { return this.connectedEdges.Count; } }
    // For now as no weights logics are defined
    public int PathWeights { get { return this.EdgeCount; } }
    public List<Edge> ConnectedEdges { get { return this.connectedEdges; } }
}

答案 1 :(得分:0)

我认为DFS(深度优先搜索)应该符合您的要求。在这看一下 - Depth First Search - Wikipedia。您可以定制它以您需要的格式打印路径。至于复杂性,由于树中的每个节点都有一个度数,因此树的边数被限制为 - | E | = O(| V |)。由于DFS的复杂度为O(| V | + | E |),因此整体复杂度为O(| V |)。

答案 2 :(得分:0)

我把这个问题作为我的任务的一部分。上面的绅士已正确指出使用pathID。您必须至少访问每个边缘一次,因此复杂性界限为O(V + E),但对于树E = O(V),因此复杂度为O(v)。我会给你一瞥,因为细节有点涉及 -

您将使用唯一ID标记每个路径,并且路径是增量值中的分配ID,例如0,1,2 ....路径的pathID是路径上边缘的权重之和。因此,使用DFS为路径分配权重。您可以先使用0作为边缘,直到遇到第一条路径,然后继续添加1,依此类推。您还必须争论正确性并正确分配权重。 DFS会做到这一点。