检测图形中的循环(使用三色机制)

时间:2016-12-02 10:15:16

标签: algorithm data-structures graph

我知道如何使用三种颜色(黑色,白色和灰色)机制检测图形中的循环。对于那些不知道这一点的人,请按照: http://www.geeksforgeeks.org/detect-cycle-direct-graph-using-colors/

简而言之,白色节点是未被发现的节点,灰色是用于正在处理的节点,黑色节点是被发现的节点。

几天前,一位资深人士问我为什么一个人为此目的需要三种颜色。为什么我们不能只用黑与白呢?为什么真的需要灰色节点?我很难说我可以回答这个问题。谁能告诉你他是在问我一个有效的问题还是只是测试我?

3 个答案:

答案 0 :(得分:3)

以下是您需要的所有解释

https://cs.stackexchange.com/questions/9676/the-purpose-of-grey-node-in-graph-depth-first-search

基本上,白色节点在您第一次访问它们后变为灰色,但灰色节点只有在所有邻居变黑后才会变黑,或者他们没有任何未访问的邻居。

  

在有向图中,当且仅当在访问所有后代之前再次看到节点时,才存在循环。换句话说,如果节点具有灰色的邻居,则存在循环(而不是当邻居是黑色时)。灰色节点意味着我们正在探索它的后代 - 如果一个这样的后代有一个边缘到这个灰色节点,那么就有一个循环。因此,对于有向图中的循环检测,您需要有3种颜色。

现在应该很清楚,两种颜色不够用。

答案 1 :(得分:2)

不,他没有对你进行测试。您可以仅使用两种颜色检测图形中的周期,但在这种情况下图形必须是无向的。

精化

我想强调的是,根据边缘的方向,图形有两种,当我们有一个图形时,我们有两个顶点前后和后面的两个顶点,图形的类型被称为无向图。

The Picture you see is of an undirected graph

以下图片是有向图。

The Directed Graph

这两者在纸上的区别在于我们不会在无向图中绘制边的方向,每当我们说在无向图的上下文中节点A和B之间存在边时,它会自动跟随反向边缘也存在。为什么我们甚至谈论反向边缘,原因是在计算机程序中边缘以不同的表示方式表示,我们仅指示有向边缘,例如在邻接列表中,节点B将仅在A的邻接列表中如果从A到B有一条边,那么在这种表示中,如果我们需要显示B到A之间存在边,那么我们还需要在B的邻接列表中添加节点A.

类似地,在基于邻接矩阵的表示的情况下,矩阵关于它的前导对角线(从左上角开始的对角线)对称,以表明对于从A到B存在的每个边缘,矩阵也存在从B到A的边缘。

因此要实现任何无向图,我们遵循

Replacing edges

因此,在您用这个替换无向图的所有边之后,您将看到计算机图形中图的实际图片。

现在假设您已获得图表。你必须问,哪一个?

无向图

我将参考此处发布的第一张图片进行讨论。并假设邻接列表表示已用于表示图形。

这看起来怎么样?在这里你看到:

A:B - > D - > E - > NULL
B:A - > D - > E - > NULL
C:D - > NULL
D:A - > B - > C - > NULL
E:A - > B - > NULL

目标是设计一些策略来检查周期是否存在。

现在假设这些节点代表城市中的一些商店而边缘是道路,因此如果您看到从节点A到B的道路,则自动存在从B到A的道路,因为图形是无向的。从邻接列表中也可以看出这一点。

要检测无向图中的循环,我们将按照以下步骤进行操作,典型程序将遵循。然后你会看到我给出的陈述是如何有效的。所以,让我们开始。

我们从节点A开始,心情遍历整个图表,遍历这里意味着您想要访问所有商店。现在要真正跟踪你所访问过的所有商店,当你离开它们时给它们上色,这样你就站在节点A,现在你已经从节点A出现了许多道路,你可以带到其他地方去。所有这些选项都出现在A的邻接列表中。

让我们说你选择一条通往Node B的道路,你跟着它,留下A,然后在离开A之前给它上色。现在站在B你首先看到,那个节点是彩色的吗?你看不到!!然后你知道你之前没有访问过这个节点。再次想要做同样的事情,所以你看到B的邻接列表选择下一条路,你看到一条通往A的道路,你再次沿着那条路走,并在你离开时到达A,颜色B.但是一旦你到达节点A,你就会看到它被着色,这意味着你之前已经访问过这个商店,但是你意识到因为图表是无向的,所以从B到达A不是问题,因为边是双向的,所以你回溯。

要再次避免这种情况,请使用父数组,其中par [i] = j,如果您从j发现了i。现在你已经消除了再次拜访父母的陷阱。现在你选择B的下一条路,即E,你去那里,颜色B,这次设置par [E] = B,当你到达E时,你想再做同样的事情。但是这次你看到了通往A的道路,首先你检查的是你的父母吗?因为当你从那里来的时候,你不想再次访问你的父母。

这里没有。所以你去A,但是一旦你到达A,你会注意到节点是彩色的。如果这是真的那么这意味着你已经访问了A,这意味着存在一条从A到A再次结束的路径,因此是一个循环。

那么告诉我我们使用了多少种颜色?只有两个,一个是初始颜色,另一个是访问节点后。

你可能会说我已经在这个具体的例子中展示了它,所以程序可能不会总是有效,但尝试通过遍历的感觉来实现我描述的情况,并尝试说服自己,如果你从节点开始并跟随一组如果你到达某个地方并且看到节点是彩色的,那就意味着你已经访问了那个节点,并且因为你正在避免访问节点的父节点,因此你可以看到一个彩色节点的唯一方法是因为一些周期。

我想让你意识到为什么这个东西在有向图中不起作用,双向边缘的机制在哪里来了。

答案 2 :(得分:0)

#include<bits/stdc++.h>
using namespace std;
list<int>adj[10000];
int flag =0;
void dfs(int s , bool visited[] , char color[]){
    visited[s] = true;
    color[s] = 'g';
    std::list<int>::iterator ii;
    for(ii=adj[s].begin() ; ii!=adj[s].end(); ii++){
        if(visited[*ii]==false){
            visited[*ii]=true;
            color[*ii]='g';
            dfs(*ii , visited , color);
        }
        else if(visited[*ii]==true && color[*ii]=='g'){
            flag=1;
        }
    }
    color[s] = 'b';
}
int main(){
    int n,m,x,y,i;
    cin>>n>>m;
    for(i=0; i<m; i++){
        cin>>x>>y;
        adj[x].push_back(y);
    }
    bool visited[n+1];
    char color[n+1];
    for(i=0; i<n; i++){
        visited[i] = false;
        color[i] = 'w';
    }
    dfs(0 , visited , color);
    if(flag==1)
    {
        cout<<"Yes"<<endl;
    }
    else{
        cout<<"No"<<endl;
    }
}