BFS遍历图节点两次

BFS traverses graph node twice

本文关键字:两次 遍历 节点 BFS      更新时间:2023-10-16

我在我的这段代码中发现了一个错误,其中图中的一个节点出现了两次。我用矢量来存储边之间的关系。非常感谢您的帮助。

#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<int> v[n+1];
for (int i = 0; i < m; ++i)
{
int a,b;
cin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
std::queue<int>q ;
q.push(1);
cout<<"And the traversal is:n";
bool visited[n+1]={false};
for(;!q.empty();){
int curr=q.front();
q.pop();
cout<<curr<<endl;
for(int i=0;i<v[curr].size();++i){
if(!visited[v[curr][i]]){
q.push(v[curr][i]);
visited[curr]=true;
}
}
}
}

我检查的输入:

5 5
1 3
3 2
2 4
3 5
5 4

输出:

And the traversal is:
1
3
2
5
4
4

您需要区分节点可能处于的三种状态:

  • 未处理(尚未看到)
  • 已发现(已排队)
  • 已处理(遍历、输出)

使用visited布尔数组,您可以在发现节点或遍历节点时对其进行标记。虽然术语"已访问"通常指的是后者,但使用前者意味着节点不会多次添加到队列中,也不需要额外的if (visited[curr]) continue;检查。

因此,要做到这一点,您需要在代码中修复两件事:

  • 初始化队列的起始节点(1)已被定义发现
  • 在当前节点的邻居的循环中,当您将visited[curr]添加到队列中时,您不能将其标记为"已发现",而必须将它标记为"发现">

cout<<"And the traversal is:n";
std::queue<int>q;
bool visited[n+1]={false};
q.push(1);
visited[1] = true;
while(!q.empty()){
int curr=q.front();
q.pop();
cout<<curr<<endl;
for(int i=0;i<v[curr].size();++i){
int target = v[curr][i]; // opposite node on edge 
if(!visited[target]){
q.push(target);
visited[target]=true;
}
}
}

下面的旧(不完整)答案
您希望将current节点设置为visited始终,而不仅仅是当它有一个尚未访问的邻居时(4实际上没有任何邻居)。将其移出循环:

for(int i=0;i<v[curr].size();++i){
if(!visited[v[curr][i]]){
q.push(v[curr][i]);
}
}
visited[curr]=true;

也许你甚至应该把它移到循环的前面,以防出现自循环边