用于检测图中循环的算法的修改

Posted

技术标签:

【中文标题】用于检测图中循环的算法的修改【英文标题】:Modification of an algorithm for detecting cycles in a graph 【发布时间】:2015-07-31 14:00:09 【问题描述】:

在下面的代码中,我检查图形是否包含循环并且它正在 100% 工作,但我确实想修改它,而不是打印是的,我希望它打印循环重复的第一个节点.因此,例如,如果实际图形有一个循环并且循环是 0,1,3,5,7,0 ,而不是我想打印 0。 或者如果循环是 1、3、5、7、8、1,它应该打印 1。如果有人知道我会很感激,谢谢。

#include<iostream>
#include <list>
#include <limits.h>
using namespace std;

// Class for an undirected graph
class Graph

    int V;    // No. of vertices
    list<int> *adj;    // Pointer to an array containing adjacency lists
    bool isCyclicUtil(int v, bool visited[], int parent);
public:
    Graph(int V);   // Constructor
    void addEdge(int v, int w);   // to add an edge to graph
    bool isCyclic();   // returns true if there is a cycle
;

Graph::Graph(int V)

    this->V = V;
    adj = new list<int>[V];


void Graph::addEdge(int v, int w)

    adj[v].push_back(w); // Add w to v’s list.
    adj[w].push_back(v); // Add v to w’s list.


// A recursive function that uses visited[] and parent to detect
// cycle in subgraph reachable from vertex v.
bool Graph::isCyclicUtil(int v, bool visited[], int parent)

    // Mark the current node as visited
    visited[v] = true;

    // Recur for all the vertices adjacent to this vertex
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
    
        // If an adjacent is not visited, then recur for that adjacent
        if (!visited[*i])
        
            if (isCyclicUtil(*i, visited, v))
                return true;
        

        // If an adjacent is visited and not parent of current vertex,
        // then there is a cycle.
        else if (*i != parent)
            return true;

    
    return false;


// Returns true if the graph contains a cycle, else false.
bool Graph::isCyclic()

    // Mark all the vertices as not visited and not part of recursion
    // stack
    bool *visited = new bool[V];
    for (int i = 0; i < V; i++)
        visited[i] = false;

    // Call the recursive helper function to detect cycle in different
    // DFS trees
    for (int u = 0; u < V; u++)
        if (!visited[u]) // Don't recur for u if it is already visited
            if (isCyclicUtil(u, visited, -1))
                return true;
            

    return false;


// Driver program to test above functions
int main()

    int res=0;
    int m, n;
    cin >> m >> n;

    Graph g1(m);
    for(int i=0; i<n; i++) 
        int q, r;
        cin >> q >> r;
        g1.addEdge(q, r);
    

    g1.isCyclic()? cout << "Yes":
    cout << "No";

    return 0;

【问题讨论】:

什么是循环的开始?循环本身没有开始。在您的示例中,如果 0、1、3、5、7、0 是一个循环 0 是第一个元素,就像 3 或 7 一样 我的意思是在这种情况下重复的第一个元素 0 是第一个重复的元素。或者如果有一个循环 1,6,7,8,9,8 ,它应该打印 8,我认为现在很清楚 :) 这是作业吗?是什么阻碍了您仅打印它? 不,不是。第一个元素取决于您开始搜索的位置。在您的第二个示例中,您可以有另一条路径首先通向 9(而不是 8)。我想说的是'第一个'lelement没有明确定义。也许您需要告诉我们更多关于“为什么”需要它的信息。 @kchoi 我很确定“循环”应该是指从 X 到 Y 的两条不同路径(概念上是从 X 到 Y 的路径和从 Y 到 X 的路径,而不是从X 到 Y)。 【参考方案1】:

一旦你找到一个循环,通过访问一个你已经访问过的节点,你就知道这个节点是循环的一部分。 然后你可以对节点本身进行深度优先搜索。找到后,输出堆栈上的所有节点。

如果您想高效地编写代码,您也可以通过这种方式找到循环,然后输出所有节点,直到到达找到循环的节点。

【讨论】:

请求是在一个循环中输出“第一个”(无论是什么意思)项目。但是您的答案旨在输出一个循环中的所有项目,即使这样,您也可能是错误的(将输出循环的父项)或缺少很多细节。 我的解决方案输出循环的所有项目。循环中没有“第一个”项目。但是,它不会输出除循环元素之外的任何其他元素(父级)。如果您的意思是“更有效”的方法:您首先深度搜索循环。一旦你找到一个循环,你标记你所在的项目,把它写出来并返回一些东西,告诉你的递归函数找到了一个循环,它应该输出它所在的元素,然后再次返回,......除非你的堆栈在标记节点处,循环结束(并因此开始)。那么这个循环就完成了。【参考方案2】:

找到一个逻辑顺序(或者只是序列化搜索顺序)并使用哈希来重复节点和已经看到的循环。打印搜索开始节点号。根据您的搜索顺序,您的结果可能会有所不同。

【讨论】:

以上是关于用于检测图中循环的算法的修改的主要内容,如果未能解决你的问题,请参考以下文章

Dijkstra 的单源最短路径算法能否检测到图中的无限循环?

在彩色图中查找具有单个不同颜色边的循环

链表循环检测算法

在图中找到一个简单循环并打印它的算法

循环有向图和无向图

SPFA算法