【问题标题】:Traverse a graph, one vertex, all possible round trips遍历一个图,一个顶点,所有可能的往返
【发布时间】:2014-06-26 03:56:25
【问题描述】:

我手头有一个有趣的问题。我想解决一个从加权图的源顶点开始的问题,并找出所有可能返回它的路径。

例如:考虑上面的有向图:


如果我从 Source=A 开始的预期输出:

1) A -> C -> D -> B-> A

2) A -> B -> A

3) A -> D -> B -> A

注意:


a) 图表将被加权,我在遍历时找到边的总和(不一定是最小总和)。

b) 计划用矩阵来表示图,图在某些地方可能是循环的。

b) 解决这个问题的最有效的代码是什么?我知道 BFS 和 DFS,但他们不计算往返!

当前 DFS 代码:(邻接图)

void dfs(int cost[][20],int v[],int n, int j)
{
int i;
v[j]=1;
printf("Vistiing %d\n",j);
for(i=0;i<n;i++)
if(cost[j][i]==1 && v[i]==0)
dfs(cost,v,n,i
);
}

【问题讨论】:

    标签: graph traversal rounding


    【解决方案1】:

    这可以通过修改DFS(或BFS)来解决。

    考虑 DFS。

    访问节点后,将其标记为已访问。从它返回后,将其标记为未访问,以便可以识别其他路径。

    你的例子:

    Start from A.
    Choose a path.
    A->B->A.
    Return to B. No other paths.
    Return to A. Mark B unvisited. Choose another path.
    A->D->B->A.
    Return to B. No other paths.
    Return to D. Mark B unvisited. No other paths.
    Return to A. Mark D unvisited. Choose another path.
    A->C->D->B->A.
    

    注意:这里重要的是标记未访问的节点。

    【讨论】:

    • 这个概念或者marking/unmarking基本可以概括为en.wikipedia.org/wiki/Backtracking,但是思路显然是可行的,所以+1
    • 我将如何使用代码实现这一点?由于我使用递归来遍历顶点,我怎么知道我什么时候返回?
    • @Marco13 我知道回溯,但我不想马上给它贴上标签。
    • 另外,由于 DFS 遍历是从已访问到未访问的顶点发生的,a->b->a 将如何工作?当我在 B 时,它被标记为已访问。此外,A 被标记为以前访问过( A->B) ,因此 (B->A) 意味着选择具有 2 个已访问节点的边??
    • @user3210476 不,未标记 A。您想在 A 往返。所以 A 没有标记。
    【解决方案2】:

    这听起来像是Backtracking 的一个很好的应用案例:

    • 从所需节点开始
    • 如果第二次到达起始节点,返回结果
    • 否则:对于每个邻居
      • 将邻居添加到当前路径
      • 进行递归
      • 从当前路径中删除邻居

    这里作为一个例子来实现。当然,这(尤其是图数据结构)只是一个速写来表明这个想法是可行的,在MCVE

    import java.util.ArrayList;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Set;
    
    
    public class GraphRoundTrips
    {
        static class Vertex
        {
            String name;
            Vertex(String name)
            {
                this.name = name;
            }
            @Override
            public String toString()
            {
                return name;
            }
        }
    
        static class Edge
        {
            Vertex v0;
            Vertex v1;
            Edge(Vertex v0, Vertex v1)
            {
                this.v0 = v0;
                this.v1 = v1;
            }
            @Override
            public String toString()
            {
                return "("+v0+","+v1+")";
            }
        }
    
        static class Graph
        {
            List<Vertex> vertices = new ArrayList<Vertex>();
            List<Edge> edges = new ArrayList<Edge>();
    
            void addVertex(Vertex v)
            {
                vertices.add(v);
            }
            void addEdge(Edge e)
            {
                edges.add(e);
            }
    
            List<Vertex> getOutNeighbors(Vertex v)
            {
                List<Vertex> result = new ArrayList<Vertex>();
                for (Edge e : edges)
                {
                    if (e.v0.equals(v))
                    {
                        result.add(e.v1);
                    }
                }
                return result;
            }
        }
    
        public static void main(String[] args)
        {
            Vertex A = new Vertex("A");
            Vertex B = new Vertex("B");
            Vertex C = new Vertex("C");
            Vertex D = new Vertex("D");
    
            Graph graph = new Graph();
            graph.addVertex(A);
            graph.addVertex(B);
            graph.addVertex(C);
            graph.addVertex(D);
    
            graph.addEdge(new Edge(A,C));
            graph.addEdge(new Edge(A,D));
            graph.addEdge(new Edge(A,B));
            graph.addEdge(new Edge(B,A));
            graph.addEdge(new Edge(C,D));
            graph.addEdge(new Edge(D,B));
    
            compute(graph, A, null, new LinkedHashSet<Vertex>());
    
        }
    
        private static void compute(Graph g, Vertex startVertex, 
            Vertex currentVertex, Set<Vertex> currentPath)
        {
            if (startVertex.equals(currentVertex))
            {
                List<Vertex> path = new ArrayList<Vertex>();
                path.add(startVertex);
                path.addAll(currentPath);
                System.out.println("Result "+path);
            }
            if (currentVertex == null)
            {
                currentVertex = startVertex;
            }
            List<Vertex> neighbors = g.getOutNeighbors(currentVertex);
            for (Vertex neighbor : neighbors)
            {
                if (!currentPath.contains(neighbor))
                {
                    currentPath.add(neighbor);
                    compute(g, startVertex, neighbor, currentPath);
                    currentPath.remove(neighbor);
                }
            }
        }
    
    
    
    }
    

    【讨论】:

    • 对不起!但我必须使用 C 来实现这个!所以我想到了使用矩阵来表示图形,否则实现将成为一场噩梦 ;(!我可以和你分享我现有的 C 代码吗?
    • @user3210476 基本方法在任何语言中都是相同的(尽管 C 比 Java 更不方便——让我们开始咆哮吧:D)。我只添加了实现,因为我刚刚尝试过它并且可以使用它,所以......为什么不呢。如果您已经开始使用 C 实现,则无论如何都应该考虑将其添加到您的问题中,并说明您遇到的问题或没有按预期工作的地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多