• C#,搜索无向无权连通图(Undirected Unweighted Graph)的简单环(Simple Cycle)的算法与源代码


     

    一、无向无权连通图

    给定一个无向无权连通图,在该图中找到一个简单的环(如果存在)。

    简单循环:

    简单循环是图中没有重复顶点的循环(起点和终点顶点除外)。

    基本上,如果一个周期不能分解为两个或两个以上的周期,那么它就是一个简单的周期。

    方法:目的是检查图表是否包含循环。这可以通过简单地使用DFS来完成。

    现在,如果图包含一个循环,我们可以从DFS本身获得该循环的端点(例如a和b)。现在,如果我们从a到b运行BFS(忽略a和b之间的直接边),我们将能够获得从a到b的最短路径,这将为我们提供包含点a和点b的最短循环的路径。通过使用父数组可以轻松跟踪路径。这个最短的周期将是一个简单的周期。

    证明最短周期为简单周期的证明:

    我们可以用矛盾来证明这一点。假设在这个循环中存在另一个简单的循环。这意味着内部简单循环的长度将更短,因此可以说从a到b的路径更短。但我们已经使用BFS找到了从a到b的最短路径。因此,不存在较短的路径,找到的路径是最短的。所以,在我们发现的周期内,不可能存在任何内部周期。

     

    此数据结构仅完成未加权图规范,不定义进一步的操作。作为一个完整的实现,它必须决定如何在其中存储顶点。选项与存储边时使用的选项相同:

    实现顶点列表的动态数组:迭代速度非常快,搜索值/顶点速度非常慢。如果顶点内的值不唯一,则使用!如果使用,边缘必须使用相同的存储选项。

    实现顶点集的哈希表:迭代速度非常快,搜索值/顶点速度非常快。如果顶点内的值唯一,则使用!如果使用,边缘必须使用相同的存储选项。

    二、图术语汇编

    术语汇编下面是我们使用的一些定义。

    自循环是将顶点连接到自身的边。

    如果两条边连接同一对顶点,则它们是平行的。

    当一条边连接两个顶点时,我们说这些顶点彼此相邻,并且该边关联在两个顶点上。

    顶点的阶数是其上关联的边数。

    子图是构成图的图的边(和相关顶点)的子集。

    图中的路径是由边连接的顶点序列,没有重复的边。

    简单路径是没有重复顶点的路径。

    循环是第一个顶点和最后一个顶点相同的路径(至少有一条边)。

    简单循环是没有重复顶点的循环(第一个和最后一个顶点的必要重复除外)。

    路径或循环的长度是其边数。

    如果存在一条包含两个顶点的路径,我们说一个顶点连接到另一个顶点。

    如果有一条从每个顶点到其他每个顶点的路径,则图是连通的

    非连通图由一组连通分量组成,这些连通分量是最大连通子图。

    无圈图是一个没有圈的图。

    是一个非循环连通图。

    森林是一组不相交的树木。

    连通图的生成树是包含该图所有顶点的子图,是一棵树。图的生成林是其连通部分的生成树的并集。

    二分图是一个图,其顶点可以分为两个集,这样所有边都可以将一个集中的顶点与另一个集中的顶点连接起来。

     

    参考:

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

    源程序:

    1. using System;
    2. using System.Text;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. namespace Legalsoft.Truffer.Algorithm
    6. {
    7. public partial class Graph
    8. {
    9. public bool Detect_Cycle(int node, int par, ref bool[] vis, out int start_node, out int end_node)
    10. {
    11. start_node = -1;
    12. end_node = -1;
    13. vis[node] = true;
    14. foreach (int child in Adjacency[node])
    15. {
    16. if (vis[child] == false)
    17. {
    18. if (Detect_Cycle(child, node, ref vis, out start_node, out end_node))
    19. {
    20. return true;
    21. }
    22. }
    23. else if (child != par)
    24. {
    25. start_node = child;
    26. end_node = node;
    27. return true;
    28. }
    29. }
    30. return false;
    31. }
    32. public List<int> Find_Simple_Cycle(int a, int b, ref bool[] vis)
    33. {
    34. List<int> simple_cycle = new List<int>();
    35. int[] par = new int[Int16.MaxValue];
    36. Queue<int> q = new Queue<int>();
    37. q.Enqueue(a);
    38. bool ok = true;
    39. while (q.Count != 0)
    40. {
    41. int node = q.Peek();
    42. q.Dequeue();
    43. vis[node] = true;
    44. foreach (int child in Adjacency[node])
    45. {
    46. if (node == a && child == b)
    47. {
    48. continue;
    49. }
    50. if (vis[child] == false)
    51. {
    52. par[child] = node;
    53. if (child == b)
    54. {
    55. ok = false;
    56. break;
    57. }
    58. q.Enqueue(child);
    59. vis[child] = true;
    60. }
    61. }
    62. if (ok == false)
    63. {
    64. break;
    65. }
    66. }
    67. simple_cycle.Add(a);
    68. int x = b;
    69. while (x != a && x > 0)
    70. {
    71. simple_cycle.Add(x);
    72. x = par[x];
    73. }
    74. return simple_cycle;
    75. }
    76. }
    77. public static partial class GraphDrives
    78. {
    79. public static string Simple_Cycle()
    80. {
    81. Graph g = new Graph(13);
    82. bool[] vis = new bool[Int16.MaxValue];
    83. g.AddEdge(1, 2);
    84. g.AddEdge(2, 3);
    85. g.AddEdge(3, 4);
    86. g.AddEdge(4, 6);
    87. g.AddEdge(4, 7);
    88. g.AddEdge(5, 6);
    89. g.AddEdge(3, 5);
    90. g.AddEdge(7, 8);
    91. g.AddEdge(6, 10);
    92. g.AddEdge(5, 9);
    93. g.AddEdge(10, 11);
    94. g.AddEdge(10, 13);
    95. g.AddEdge(11, 12);
    96. g.AddEdge(11, 13);
    97. g.AddEdge(12, 13);
    98. StringBuilder sb = new StringBuilder();
    99. if (g.Detect_Cycle(9, -1, ref vis, out int start_node, out int end_node) == true)
    100. {
    101. for (int i = 0; i < vis.Length; i++)
    102. {
    103. vis[i] = false;
    104. }
    105. List<int> simple_cycle = g.Find_Simple_Cycle(9, 10, ref vis);
    106. sb.AppendLine("A simple cycle: ");
    107. foreach (int node in simple_cycle)
    108. {
    109. sb.AppendLine(node + " => ");
    110. }
    111. sb.AppendLine(start_node + "");
    112. sb.AppendLine("<br><br>");
    113. }
    114. else
    115. {
    116. sb.AppendLine("The Graph doesn't contain a cycle j=9.<br>");
    117. }
    118. return sb.ToString();
    119. }
    120. }
    121. }

  • 相关阅读:
    关于ROS的网络通讯方式TCP/UDP
    nginx location / 区别
    Docker数据卷
    PostgreSQL 的 Replication Slot分析研究
    如何介绍自己的项目经验?
    详细步骤记录:持续集成Jenkins自动化部署一个Maven项目
    java (gc)机制
    SpringBoot开启定时任务
    软件性能测试指标分享,第三方检测机构进行性能测试的好处
    联想服务器-HTTP boot安装Linux系统
  • 原文地址:https://blog.csdn.net/beijinghorn/article/details/125510450