当前位置:   article > 正文

有向无环图讲解及模板(C++代码)

有向无环图

一、有向无环图

一个无环有向图做有向无环图(Directed Acyclic Graph)。简称DAG 图

图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。

有向无环图

因为有向图中一个点经过两种路线到达另一个点未必形成环,因此有向无环图未必能转化成树,但任何有向树均为有向无环图。

使用有向无环图解题时,要先判断是否是有向无环题。如果任务x必须在任务y之前完成:x→y,而y→z。也就是说一般在涉及优先级限制的问题时,使用有向无环图的方法。

注意与并查集进行区分

关于并查集模板:https://blog.csdn.net/qq_41687938/article/details/112850265

二、有向无环图求解过程

做有向无环图题的时候,一共就三步:

1.根据题目意思及输入,理清两节点间的指向关系,构建由前指向后的有向无环图

也就是构建一个map,key为当前节点,val数组为当前节点指向的那些节点。

2.根据有向无环图,统计每个节点出现的次数,因为有的节点已经出现过,但还是可能由其他指向路径的节点再指回来,在输出的时候需要遍历其最后出现的地方,所以要记一下它出现的次数。

其中,头节点的次数记为-1,并将头节点保存起来,方便接下来的遍历。

3.因为有向无环图的输出一般都有要求按大小关系输出(本文按升序输出!),也就是构建一个优先队列来完成节点输出。每遍历一个节点就将其所指向的节点压入队列中,实现了某节点的下一层与当前节点层的其他节点的比较。并将遍历到的节点输出。直到队列中所有节点输出。

2.1 具体看题:

一个完整的软件项目往往会包含很多由代码和文档组成的源文件。编译器在编译整个项目的时候,可能需要按照依赖关系来依次编译每个源文件。比如,A.cpp 依赖 B.cpp,那么在编译的时候,编译器需要先编译 B.cpp,才能再编译 A.cpp。 假设现有 0,1,2,3 四个文件,0号文件依赖1号文件,1号文件依赖2号文件,3号文件依赖1号文件,则源文件的编译顺序为 2,1,0,3 或 2,1,3,0。现给出文件依赖关系,如 1,2,-1,1,表示0号文件依赖1号文件,1号文件依赖2号文件,2号文件没有依赖,3号文件依赖1号文件。请补充完整程序,返回正确的编译顺序。注意如有同时可以编译多个文件的情况,按数字升序返回一种情况即可,比如前述案例输出为:2,1,0,3

输入例子1:

"1,2,-1,1"

输出例子1:

"2,1,0,3"

三、C++代码模板: 

  1. class Solution {
  2. public:
  3. string compileSeq(string input) {
  4. //首先完成有向无环图的构建
  5. //统计图中各节点的个数 并标记头节点为-1
  6. //使用优先队列 按照先小后大的顺序遍历输出节点值
  7. int len = input.size();
  8. /*********构建有向无环图(指向关系)*********/
  9. map<int, vector<int>> mp;//first为先 second为后, 也就是second依赖于first
  10. string tmp;
  11. int idx = 0;
  12. for(auto& s:input){
  13. if(s != ',')
  14. tmp += s;
  15. else{
  16. mp[stoi(tmp)].push_back(idx++);
  17. string().swap(tmp);//清空string
  18. }
  19. }
  20. if(!tmp.empty())
  21. mp[stoi(tmp)].push_back(idx++);
  22. /**********统计各节点个数 并保存头节点***********/
  23. vector<int> indexcount(len, 0);//统计各节点个数
  24. priority_queue<int, vector<int>, greater<>> pq;//保存节点
  25. for(auto& m:mp){
  26. if(m.first == -1){
  27. for(auto& a:m.second){
  28. pq.push(a);
  29. indexcount[a] = -1;
  30. }
  31. }else{
  32. for(auto& a:m.second)
  33. ++indexcount[a];
  34. }
  35. }
  36. /************根据指向关系遍历图 并按照优先队列输出结果********/
  37. vector<int> ans;
  38. while(!pq.empty()){
  39. int node = pq.top();
  40. pq.pop();//输出了就需要从优先队列中弹出
  41. ans.push_back(node);
  42. for(auto& m:mp[node]){
  43. if(--indexcount[m] == 0)//如果该节点是最后一次在图中出现 则放入队列中
  44. pq.push(m);
  45. }
  46. }
  47. /***********输出结果************/
  48. string res;
  49. for(auto& i:ans){
  50. res += to_string(i);
  51. res.push_back(',');
  52. }
  53. if(!res.empty())
  54. res.pop_back();
  55. return res;
  56. }
  57. };

 

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/258191
推荐阅读
相关标签
  

闽ICP备14008679号