检查无向图中节点 S 和 T 之间是否存在仅 S 和 T 重复的环路


介绍

图是一种强大的数学结构,允许我们对各种实体之间的关系进行建模和可视化。在计算机科学中,图在各种算法和数据结构中都有应用。无向图的一个常见问题是确定两个给定节点之间是否存在环路。在本文中,我们将着手解决这个难题,并使用 C/C++ 提供一个优雅的解决方案。确定无向图中的环路对于各种连接性很重要的应用至关重要。

无向图是确定两个给定节点之间是否存在环路

无权双向(或无向)图由通过边连接的顶点或节点组成。这些边没有分配任何特定的权重或距离,而是仅指示存在连接,没有任何方向偏差。

路径表示一系列互连的顶点,其中每个顶点都通过边直接与其相邻的对应顶点连接。在这里,我们专注于查找连接两个不同顶点(明确称为源节点和目标节点)的路径,并具有最小的总边遍历次数。

考虑一个无向图,其中每条边表示两个节点之间的连接。我们的目标是确定在这个图中是否存在连接节点 S 和节点 T 的环路,当这两个节点都可以在任何路径中重复出现。

在上图中,它有四个顶点和 3 条边,我们需要检查节点 1 和节点 4 之间是否存在环路。DFS 算法从节点 1(源节点)开始,访问其相邻节点 - 节点 2 和节点 3。然后它访问节点 4,该节点之前已被节点 3 访问过。由于节点 4 不是节点 3 的父节点,因此图中存在环路。

方法 1:C++ 程序,用于检查无向图中节点 S 和 T 之间是否存在仅 S 和 T 重复的环路

为了有效地解决这个问题,我们将采用深度优先搜索 (DFS),这是一种广泛使用的图遍历算法。DFS 背后的基本思想是尽可能沿着每个分支向下探索,然后再回溯。

算法

  • 步骤 1 − 它使用一个 `Graph` 类来封装图的属性。

  • 步骤 2 − 它包括诸如 `addEdge()`(连接两个顶点)、`hasCycle()`(确定两个节点之间是否存在环路)以及用于 DFS 遍历的内部辅助方法(例如 `dfsUtil()`)之类的函数。

  • 步骤 3 − 在驱动程序代码 (`main()` )中,我们提示用户输入图中的顶点数和边数。

  • 步骤 4 − 然后逐一询问边对(节点连接)。

  • 步骤 5 − 最后,询问源顶点和目标顶点。

  • 步骤 6 − 程序将输出这两个节点之间是否存在可能重复的路径。

示例

#include <iostream>
#include <vector>

using namespace std;

// Graph class representing our underlying structure
class Graph {
   int numNodes; // Total number of nodes in the graph
   vector<vector<int>> adjList; // Adjacency list representation
    
   public:
      // Constructor taking input parameter specifying the total number of nodes
      Graph(int n) {
         numNodes = n;
         adjList.resize(n);
      }
    
      // Function allowing adding edges between two vertices u and v (0-based indexing)
      void addEdge(int u, int v) {
         adjList[u].push_back(v);
         adjList[v].push_back(u);
      }
    
   private:
      // Utility function used by hasCycle() to perform DFS search recursively starting from vertex s.
      // It returns true if the cycle is found during exploration.
      bool dfsUtil(int s, bool visited[], bool parent[]) {
         visited[s] = true;
    
         for (int v : adjList[s]) {
            if (!visited[v]) {
               parent[v] = true;
            
               // Recursive call
               if (dfsUtil(v, visited, parent))
                  return true;
            }
            else if(parent[v])
               return true;
         }
        
         return false;   
      }
    
   public:
      // Function that checks whether a cycle exists between nodes S and T.
      bool hasCycle(int s, int t) {
         bool* visited = new bool[numNodes];
         bool* parent = new bool[numNodes];
        
         for(int i=0; i<numNodes; ++i){
            visited[i]=false;
            parent[i]=false;
         }
         parent[s] = true;

         if(dfsUtil(s, visited, parent)){
            delete[] visited;
            delete[] parent;

            return dfsUtil(t,visited,parent);
         }
     
         delete[] visited;

         return false; 
      }

};
int main() {
   int numVertices = 4;
   int numEdges = 4;

   Graph graph(numVertices);

   vector<pair<int,int>> edges = {{1,2},{2,3},{3,4},{4,1}};

   for(auto edge : edges){
      int u = edge.first - 1;
      int v = edge.second - 1;
      graph.addEdge(u,v);
   }

   int source = 1 - 1;
   int target = 4 - 1;

   if(graph.hasCycle(source,target))
      cout<<"A cycle exists between node "<< source+1 <<" and node " <<target+1<<".";
   else
      cout<<"No cycle found between node "<< source+1<<" and node " <<target + 1<<".";

   return 0;
}

输出

A cycle exists between node 1 and node 4.

结论

当可以通过在不同路径上重复特定节点来形成环路时,这个问题变得更加有趣。通过利用深度优先搜索 (DFS),我们已经成功开发出健壮的 C++ 代码,该代码包含用于探索图的解决方案,同时有效地检查连接所选节点 S 和 T 的重复项的环路是否存在。

更新于:2023年8月25日

94 次浏览

开启你的职业生涯

通过完成课程获得认证

开始
广告
© . All rights reserved.