所以,我为DFS制作了以下代码:
void dfs (graph * mygraph, int foo, bool arr[]) // here, foo is the source vertex
{
if (arr[foo] == true)
return;
else
{
cout<<foo<<"\t";
arr[foo] = true;
auto it = mygraph->edges[foo].begin();
while (it != mygraph->edges[foo].end())
{
int k = *it;
if (arr[k] == false)
{
//cout<<k<<"\n";
dfs(mygraph,k,arr);
//cout<<k<<"\t";
}
it++;
}
}
//cout<<"\n";
}
现在,我在无向图中读到,如果在DFS时,它再次返回到同一个顶点,则有一个循环。因此,我所做的就是这个,
bool checkcycle( graph * mygraph, int foo, bool arr[] )
{
bool result = false;
if (arr[foo] == true)
{
result = true;
}
else
{
arr[foo] = true;
auto it = mygraph->edges[foo].begin();
while (it != mygraph->edges[foo].end())
{
int k = *it;
result = checkcycle(mygraph,k,arr);
it++;
}
}
return result;
}
但是,即使它们没有循环,我的checkcycle函数也会返回true。这是为什么?我的功能有问题吗?没有执行问题,否则我会调试,但他们的逻辑似乎有些不对劲。
答案 0 :(得分:2)
请注意,您的功能并不像您认为的那样完成。让我试着逐步了解这里发生的事情。假设以下关系:(1,2),(1,3),(2,3)。我没有假设反射性(即(1,2)并不暗示(2,1))。关系是有针对性的。
check cycle
。此时,2也被标记为已访问。false
false
true
。您需要一堆访问过的节点,或者只搜索原始节点。堆栈也将检测子循环(不包括原始节点的循环),但它也需要更多内存。
编辑:节点堆栈不仅仅是一堆true
/ false
值,而是一堆节点号。如果节点已存在于堆栈中,则当前堆栈跟踪中已访问该节点。
然而,这是一种更加内存友好的方式:在呼叫死亡时设置arr[foo] = false;
。像这样:
bool checkcycle( graph * mygraph, int foo, bool arr[], int previousFoo=-1 )
{
bool result = false;
if (arr[foo] == true)
{
result = true;
}
else
{
arr[foo] = true;
auto it = mygraph->edges[foo].begin();
while (it != mygraph->edges[foo].end())
{
int k = *it;
// This should prevent going back to the previous node
if (k != previousFoo) {
result = checkcycle(mygraph,k,arr, foo);
}
it++;
}
// Add this
arr[foo] = false;
}
return result;
}
我认为这应该足够了。
编辑:现在应该支持无向图。 节点:此代码未经过测试
编辑:有关更详细的解决方案,请参阅Strongly Connected Components
编辑:尽管在评论中给出了具体的解决方案,但这个答案仍然被市场所接受。阅读评论以获取详细信息。
答案 1 :(得分:0)
在检查周期开始之前,arr []中的所有bool都设置为false吗?
你确定节点的迭代器没有加倍回到它已遍历的边缘(因此无论周期如何都会多次看到起始节点)?