• C#,加权有向无环图(DAG,Directed Acyclic Graph)的最长路径(Longest Path)算法与源程序


     

    给定一个加权有向无环图(DAG)和其中的源顶点s,求出从s到给定图中所有其他顶点的最长距离。

    一般图的最长路径问题不像最短路径问题那么容易,因为最长路径问题不具有最优子结构性质。事实上,对于一般图来说,最长路径问题是NP难问题。然而,对于有向无环图,最长路径问题具有线性时间解。该思想类似于有向无环图中最短路径的线性时间解。,我们使用拓扑排序。

    我们将到所有顶点的距离初始化为负无穷大,到源的距离初始化为0,然后找到图的拓扑排序。图的拓扑排序表示图的线性排序(参见下文,图(b)是图(a)的线性表示)。一旦我们有了拓扑顺序(或线性表示),我们就会按照拓扑顺序逐个处理所有顶点。对于正在处理的每个顶点,我们使用当前顶点的距离更新其相邻顶点的距离。

     

    最长路径问题是在地图中找到长度最大的简单路径的问题;换句话说,在图中所有可能的简单路径中,问题是找到最长的路径。对于未加权图,需要根据边的数量找到最长路径;对于加权图,必须使用边权重。为了解释开发该算法的过程,我们将首先开发一种用于计算无权有向无环图(DAG)的单源最长路径的算法,然后将其推广到计算DAG中的最长路径,无论是无权路径还是加权路径。我们已经了解了如何计算图中的单源最短路径cylicor acyclic-我们使用BFS计算未加权图的单源最短路径,并使用Dijkstra(仅限非负边权重)或Bellman Ford(允许负边权重)计算无负圈的加权图。如果我们需要所有对之间的最短路径,我们总是可以使用每个顶点作为源来运行单源最短路径算法;当然,弗洛伊德·沃沙尔已经做好了这样做的准备。最短路径问题具有最优子结构,这使得使用动态规划或贪婪算法成为可能——两个顶点之间最短路径中的子路径本身必须是最短的!然而,在寻找最长路径时,我们发现问题没有最优子结构,我们失去了使用动态规划的能力(当然还有贪婪策略!)。

    最长路径算法的主要应用是在调度方面。假设我们有一个大项目,比如说,建造一座房子,它由许多小项目组成:挖掘地基、建造墙壁、连接煤气、电力和水、建造屋顶、进行室内装饰、美化环境等等。

    其中一些活动需要在他们之前完成其他活动(你不能在建墙之前盖屋顶;你不想在挖水线之前进行景观美化),而其他活动可以同时完成(完成内部装饰和景观美化)。每个子作业都有完成它所需的预期时间;您想提前知道整个任务需要多长时间,以及何时应该完成各种子任务,以便您可以安排承包商。

    从一系列这样的工作中,我们将构造一个加权的、有向的、非循环图。边将是子作业。每条边的权重将是作业的预期时间长度。

     

    最长路径算法

    现在,我们描述一种算法,用于查找从起始顶点S到所有其他顶点的最长路径。在某些方面,它类似于Dijkstra的算法,因为我们将保留一个“迄今为止发现的暂定最长路径”列表,并将其中一条到顶点v的路径迭代标记为实际最长路径,然后通过将到v的最长路径与v的边相结合,用可能新的最长路径更新我们的列表。

    主要区别在于,将在开始时选择此更新的顺序——任何与有向图结构兼容的顶点顺序都将起作用。这些排序有时被称为“拓扑排序”。

    拓扑排序

    最长路径算法的第一步是对图的顶点进行编号/列出,以便所有边从较低的顶点流向较高的顶点。这样的列表称为顶点的“兼容总排序”,或顶点的“拓扑排序”。要存在这样一个列表,图必须是非循环的。否则,我们会问“先来的是什么,鸡还是蛋?”键入情况。例如,如果我们有一个有向循环a→B→C→A、 我们不能选择A、B、C中的任何一个放在第一位,因为每个顶点都有一个来自其他顶点的错误。

    在我们运行的示例图中,顶点已经以与边结构兼容的方式进行了编号,因此已经进行了拓扑排序:S,1,2,3,4,F是满足所需属性的排序。

    事实证明,这是唯一的障碍,只要图是非循环的,它就会有一个兼容的全序。用归纳法仔细地证明这一点并不太难,将证明转化为一个构造性的算法,转化为如何做到这一点,我们邀请您这样做。然而,在小图的实践中,通常不难找到总排序。从一个源(一个没有传入边、只有传出边的顶点)开始,然后继续查找只有来自列表中已存在顶点的传入边的顶点。

    最后,我们应该强调顶点的拓扑排序通常不是唯一的。例如,在我们的运行示例中,2和3之间没有边,因此不是S,而是1,2,3,4,F

    我们可以将顶点排序为S、1、3、2、4、F,这也是一个总排序。选择哪种总排序无关紧要——最长路径算法仍然有效。在实际应用中,有效的总排序通常是“显而易见的”。

    参考:

    C#,图(Graph)的数据结构设计与源代码icon-default.png?t=M5H6https://blog.csdn.net/beijinghorn/article/details/125133711

    源代码(POWER BY 315SOFT.COM

    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. namespace Legalsoft.Truffer.Algorithm
    5. {
    6. public partial class Graph
    7. {
    8. private void Topological_Sort_Utility(int v, bool[] visited, Stack<int> stack)
    9. {
    10. visited[v] = true;
    11. for (int i = 0; i < Adjacency[v].Count; i++)
    12. {
    13. Edge e = FindEdge(v, Adjacency[v][i]);
    14. if (e == null) continue;
    15. if (!visited[e.Second])
    16. {
    17. Topological_Sort_Utility(e.Second, visited, stack);
    18. }
    19. }
    20. stack.Push(v);
    21. }
    22. public int[] Longest_Path(int s)
    23. {
    24. Stack<int> stack = new Stack<int>();
    25. int[] dist = new int[Node_Number];
    26. bool[] visited = new bool[Node_Number];
    27. for (int i = 0; i < Node_Number; i++)
    28. {
    29. visited[i] = false;
    30. }
    31. for (int i = 0; i < Node_Number; i++)
    32. {
    33. if (visited[i] == false)
    34. {
    35. Topological_Sort_Utility(i, visited, stack);
    36. }
    37. }
    38. for (int i = 0; i < Node_Number; i++)
    39. {
    40. dist[i] = int.MinValue;
    41. }
    42. dist[s] = 0;
    43. while (stack.Count > 0)
    44. {
    45. int u = stack.Peek();
    46. stack.Pop();
    47. if (dist[u] != int.MinValue)
    48. {
    49. for (int i = 0; i < Adjacency[u].Count; i++)
    50. {
    51. Edge e = FindEdge(u, Adjacency[u][i]);
    52. if (e == null) continue;
    53. if (dist[e.Second] < dist[u] + e.Weight)
    54. {
    55. dist[e.Second] = dist[u] + e.Weight;
    56. }
    57. }
    58. }
    59. }
    60. return dist;
    61. }
    62. }
    63. public static partial class GraphDrives
    64. {
    65. public static string Longest_Path()
    66. {
    67. Graph g = new Graph(6);
    68. g.AddEdge(0, 1, 5);
    69. g.AddEdge(0, 2, 3);
    70. g.AddEdge(1, 3, 6);
    71. g.AddEdge(1, 2, 2);
    72. g.AddEdge(2, 4, 4);
    73. g.AddEdge(2, 5, 2);
    74. g.AddEdge(2, 3, 7);
    75. g.AddEdge(3, 5, 1);
    76. g.AddEdge(3, 4, -1);
    77. g.AddEdge(4, 5, -2);
    78. int s = 1;
    79. int[] dist = g.Longest_Path(s);
    80. return String.Join(",", dist);
    81. }
    82. }
    83. }

  • 相关阅读:
    洛谷2022SCP第一轮J组模拟题(LGR-2022-J1)部分题解
    [附源码]计算机毕业设计JAVA航空售票管理系统
    信息学奥赛一本通:1117:整数去重
    实战演练 | Navicat 安全可靠的数据传输功能
    基于SpringBoot的在线拍卖系统
    用async函数和await解决回调函数地狱
    PCF+fluentUI开发组件并导入Microsoft Power Platform Power App
    c#设计模式-行为型模式 之 命令模式
    java检验mp4文件完整性的一个方法:使用ffmpeg
    3、matlab单目相机标定原理、流程及实验
  • 原文地址:https://blog.csdn.net/beijinghorn/article/details/125438457