问题描述
我写了bfs来查找到其他每个节点的最短路径:
queue<int> q;
dist[s] = 0; // maintains the distance of vertices from s(source).
q.push(s);
while(!q.empty()){
int src = q.front();
q.pop();
vis[src] = 1; // visited array to keep track of nodes which have been visited
for(int i=0; i<adj[src].size(); i++){ // adj is an adjacency list
if(!vis[adj[src][i]]){
q.push(adj[src][i]);
dist[adj[src][i]] = 6+dist[src];
}
}
}
这会给某些未知的测试用例带来错误的响应和超时。 但是当我这样做时,它通过了所有测试用例:
queue<int> q;
dist[s] = 0;
vis[s] = 1;
q.push(s);
while(!q.empty()){
int src = q.front();
q.pop();
for(int i=0; i<adj[src].size(); i++){
if(!vis[adj[src][i]]){
q.push(adj[src][i]);
dist[adj[src][i]] = 6+dist[src];
vis[adj[src][i]] = 1;
}
}
}
我不知道为什么会这样。
问题链接:https://www.hackerrank.com/challenges/bfsshortreach/problem
解决方法
我假设当您命名数组vis
时,它代表is_node_visited
,并且当且仅当节点is_node_visited[n]
为真时,您希望n
为真参观过。
这是问题所在。 BFS的正确概念是is_node_enqueued
。当且仅当节点is_node_enqueued[n]
曾经排队时,我们希望n
为真。第二个代码正是这样做的(除了数组仍然令人困惑地称为vis
)。
之所以需要is_node_enqueued
而不是is_node_visited
是因为您可能将同一节点排队两次。这是一个简单的例子,说明如何发生:
N1 -> N2
N1 -> N3
N2 -> N4
N3 -> N4
然后我们从N1开始'BFS'。
- 访问
N1
时,它会排队N2
和N3
。 - 访问
N2
时,它会排队N4
。 - 访问
N3
时,尚未访问N4。
这是一个有趣的时刻-如果您仅在访问N4
时才使用前者(即不正确的概念)来停止排队。 N4
将再次入队。如果您在下面使用正确的概念,则该算法将注意到N4
已入队,不会再次入队。
BFS的线性性能建立在一个节点仅被处理一次的前提之上。如果使用错误的版本,则会破坏该假设,因此您将不再在线性时间内处理图形。这就是为什么您超时的原因。
通常,用于诊断此类问题。一个有效的方法是生成一些随机输入。运行这两个程序,直到产生不同的结果,然后对导致问题的原因进行调试。