简体   繁体   English

找到有向图C ++的最短路径

[英]Finding the shortest paths of a directed graph C++

Over the last week, I have implemented a Digraph by parsing an input file. 在过去的一周里,我通过解析输入文件实现了Digraph。 The graph is guaranteed to have no cycles. 图表保证没有周期。 I have successfully created the graph, used methods to return the number of vertices and edges, and performed a topological sort of the graph. 我已经成功创建了图形,使用了返回顶点和边数的方法,并对图形进行了拓扑排序。 The graph is composed of different major courses and their prereqs. 该图由不同的主要课程及其先决条件组成。 Here is my graph setup: 这是我的图表设置:

class vertex{
public:
    typedef std::pair<int, vertex*> ve;     
    std::vector<ve> adjacency;              
    std::string course;                     
    vertex(std::string c){
        course = c;
    }
};

class Digraph{
public:
    typedef std::map<std::string, vertex *> vmap;           
    vmap work;
    typedef std::unordered_set<vertex*> marksSet;           
    marksSet marks;
    typedef std::deque<vertex*> stack;                      
    stack topo;
    void dfs(vertex* vcur);                                 
    void addVertex(std::string&);                           
    void addEdge(std::string& from, std::string& to, int cost);     
    int getNumVertices();                                   
    int getNumEdges();                                      
    void getTopoSort();                                     

};

The implementation 实施

//function to add vertex's to the graph
void Digraph::addVertex(std::string& course){
    vmap::iterator iter = work.begin();
    iter = work.find(course);
    if(iter == work.end()){
        vertex *v;
        v = new vertex(course);
        work[course] = v;
        return;
    }
}

//method to add edges to the graph
void Digraph::addEdge(std::string& from, std::string& to, int cost){
    vertex *f = (work.find(from)->second);
    vertex *t = (work.find(to)->second);
    std::pair<int, vertex *> edge = std::make_pair(cost, t);
    f->adjacency.push_back(edge);
}

//method to return the number of vertices in the graph
int Digraph::getNumVertices(){
    return work.size();
}

//method to return the number of edges in the graph
int Digraph::getNumEdges(){
    int count = 0;
    for (const auto & v : work) {
         count += v.second->adjacency.size();
     }
     return count;
}

//recursive function used by the topological sort method
void Digraph::dfs(vertex* vcur) {
  marks.insert(vcur);
  for (const auto & adj : vcur->adjacency) {
    vertex* suc = adj.second;
    if (marks.find(suc) == marks.end()) {
      this->dfs(suc);
    } 
  }
  topo.push_front(vcur);
}

//method to calculate and print out a topological sort of the graph
void Digraph::getTopoSort(){
    marks.clear();
    topo.clear();
    for (const auto & v : work) {
        if (marks.find(v.second) == marks.end()) {
            this->dfs(v.second);
        }
    }
    // Display it
   for (const auto v : topo) {
    std::cout << v->course << "\n";
  }
}

For the last part of my implementation, I have been trying to do 2 things. 对于我实施的最后一部分,我一直在尝试做两件事。 Find the shortest path from the first vertex to every other vertices, and also find the shortest path that visits every vertex and returns to the first one. 找到从第一个顶点到每个其他顶点的最短路径,并找到访问每个顶点并返回到第一个顶点的最短路径。 I am completely lost on this implementation. 我完全迷失在这个实现上。 I assumed from reading I need to use Dijkstra's algorithm to implement this. 我从阅读中假设我需要使用Dijkstra的算法来实现这一点。 I have been trying for the last 3 days to no avail. 我一直在尝试过去3天无济于事。 Did i set up my digraph in a bad way to implement these steps? 我是否以不好的方式设置了我的图表来实现这些步骤? Any guidance is appreciated. 任何指导表示赞赏。

The fact that there are no cycles makes the problem much simpler. 没有循环的事实使问题变得更加简单。 Finding the shortest paths and a minimal "grand tour" are O(n). 找到最短的路径和最小的“盛大游览”是O(n)。

Implement Dijkstra and run it, without a "destination" node; 实现Dijkstra并运行它,没有“目标”节点; just keep going until all nodes have been visited. 继续前进,直到所有节点都被访问过。 Once every node has been marked (with its distance to the root), you can start at any node and follow the shortest (and only) path back to the root by always stepping to the only neighbor whose distance is less than this one. 一旦标记了每个节点(与根节点的距离),您就可以从任何节点开始,并按照最短(且唯一)的路径返回到根节点,始终踩到距离小于此距离的唯一邻居。 If you want, you can construct these paths quite easily as you go, and mark each node with the full path back to the root, but copying those paths can push the cost to O(n 2 ) if you're not careful. 如果需要,您可以非常轻松地构建这些路径,并使用完整路径将每个节点标记回根目录,但是如果您不小心,复制这些路径可以将成本推到O(n 2 )。

And once all the nodes are marked, you can construct a minimal grand tour. 一旦所有节点都被标记,您就可以构建一个最小的游览。 Start at the root; 从根开始; when you visit a node, iterate over its unvisited neighbors (ie all but the one you just came from), visiting each, then go back the one you came from. 当你访问一个节点时,迭代它的未访问的邻居(即除你刚来的那个之外的所有邻居),访问每个,然后返回你来自的那个。 (I can put this with more mathematical rigor, or give an example, if you like.) (如果你愿意的话,我可以用更严格的数学方法来表达这一点,或者给出一个例子。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM