使用BFS算法找到最短路径

时间:2013-06-18 20:51:43

标签: c++ algorithm graph

std::list <int> q;
std::vector<bool> visited(cols + 1);
for(int i = 1; i <= cols; i++) visited[i] = false;
visited[x] = true;
if(!l[x].empty())
{
    for(std::list<int>::iterator i = l[x].begin(); i != l[x].end(); i++)
    {
        q.push_back(x); q.push_back(* i);
    }
    while(!q.empty())
    {
        y = q.back(); q.pop_back();
        x = q.back(); q.pop_back();
        if(!visited[y])
        {
            visited[y] = true;
            if(!l[y].empty())
            for(std::list<int>::iterator i = l[y].begin(); i != l[y].end(); i++)
            {
                if(!visited[*i])
                {q.push_back(y); q.push_back(* i);}
            }
            dfst[x].push_back(y);
            if(flag != 0) dfst[y].push_back(x);
        }
    }
}

这是我在图中查找生成树的DFS算法。我需要将它转换为BFS算法,找到两个顶点之间的最短路径。嗯......我怎么能这样做? BFS算法有点类似于上面的那个吗?或者我是否需要从头开始编写它?

l - 邻接清单 dfst - 最后持有生成树的数组 x - 起始顶点 y - 辅助变量

4 个答案:

答案 0 :(得分:3)

DFS和BFS本质上是相同的算法。诀窍在于您使用的数据结构,或者您首先要探索的节点。

深度优先搜索使用堆栈,因此在返回算法之前会尽可能地向下移动。

要利用广度优先搜索,您需要使用节点队列,并探索每个节点,将其邻居(如果尚未访问)添加到队列中,然后处理父节点的其余邻居,然后再继续起。

这不会对您的代码进行大幅改动,只会改变您从列表中获取节点的方式。

不要弹出背面,而只需使用q.pop_front()来获取节点。

答案 1 :(得分:3)

BFS与DFS类似。您可以查看深度为1的所有节点,然后查看深度为2的所有节点,直到您访问所有节点,而不是尽可能深入地进行回溯和重复。

基本算法:

 -Choose a starting node and add to LookQueue
 -look at all nodes directly touching and add them to LookQueue
 -when you've looked at them all
    -look at all nodes in LookQueue (removing them as you do)
    and look at all nodes touching them (adding them as you do)
       -repeat until all nodes are visited

答案 2 :(得分:2)

寻找最短路径 (用C ++ / C ++ 11编写)

我认为这一点非常重要,特别是因为标题位于最短路径上!(下面的代码实际上允许您找到一个) 此外: 如上所述(在第二个回复的评论中)DFS和BFS几乎不是(!)相同的算法,代码中的相似性,其中用队列替换堆栈并允许您从一个跳转到另一个不使它们“基本相同”。到目前为止,BFS是在未加权图中找到最短路径的更好/正确的(在两者之间)。 BFS正在从源头构建图层,而DFS正在尽可能深入。

实际上在运行BFS(找到最短路径)时,您应该使用带有非常大数字的“距离”参数初始化节点,而使用访问过的DS,将其更新为父距离+ 1(仅当它是仍然具有初始化值。)

简单示例如下:

#include <iostream>
#include <vector>
#include <queue>
#include <limits>

using namespace std;
const int imax = std::numeric_limits<int>::max();
using vi = vector<int>;

/* printPath - implementation at the end */    
void
printPath(int s, int t, const vi &path);

/*input:
* n is number of the nodes in the Graph
* adjList holds a neighbors vector for each Node
* s is the source node
*/

void dfs(int n, vector<vi> adjList, int s)
{
    //imax declared above as the max value for int (in C++)
    vector<int> distance(n, imax);
    vi path;
    queue<int> q; q.push(s); distance[s] = 0;

    while (!q.empty()) {
        auto curr = q.front(); q.pop();

        for (int i = 0; i < (int)adjList[curr].size(); ++i) {
            if (distance[i] == imax) {
                distance[i] = distance[curr] + 1;
                //save the parent to have the path at the end of the algo.
                path[i] = curr;
            }
        }//for
    }//while
     /* t can be anything you want */
    int t = 5;
    printPath(s, t, path); cout << endl;
}

/* print the shortest path from s to t */ 
void
printPath(int s, int t, const vi &path)
{
    if (t == s) {
        return;
    }
    printPath(s, path[t], path);
    cout << path[t];
}

受史蒂文&amp; amp; Felix,来自: Competitive Programming 3

答案 3 :(得分:0)

不,您不必在代码中进行太多更改。只需在带有队列的DFS的情况下替换替换堆栈,它将成为BFS。

BFS和DFS的实现差异在于“BFS是使用Queue实现的,而DFS正在使用Stack”(原因很明显,DFS在迷宫中的确如此深度。)

自己看看变化:

DFS:

void dfs(int start)
{
    int j,temp; 
    stack<int> s; //STACK
    s.push(start);
    vector<int>:: iterator it;
    while(s.empty()==0)
    {
        temp=s.top(); // Top element from Stack
        s.pop();
        status[temp]=1; // marked as visited , 0 means unvisited
        cout<<temp<<endl; // visited element
        for(it=list[temp].begin();it!=list[temp].end();it++)
        {
            j=*it;
            if(status[j]==0)
            {
                s.push(j);
                status[j]=2;    // means that it is in stack        
            }
        }

    }
}

BFS:

void bfs(int start)
{
    int j,temp; 
    queue<int> q; // QUEUE
    q.push(start);
    vector<int>:: iterator it;
    while(q.empty()==0)
    {
        temp=q.front(); // Front element from Queue
        q.pop();
        status[temp]=1; // marked as visited , 0 means unvisited
        cout<<temp<<endl; // visited element
        for(it=list[temp].begin();it!=list[temp].end();it++)
        {
            j=*it;
            if(status[j]==0)
            {
                q.push(j);
                status[j]=2;    // means that it is in queue        
            }
        }

    }
}

正如你所看到的,两者的实现只是“使用STACK和QUEUE”。

希望这有帮助!