BFS路径C ++实现返回返回一个额外的值

时间:2015-04-11 23:56:54

标签: c++ c++11 breadth-first-search

我正在尝试使用广度优先搜索来实现一个函数来查找给定开始和结束节点的路径。我是c ++的新手,我已经在python中实现了相同的功能。

使用下图,它应该给出路径{{1, 3, 6}, {1, 2, 5, 6}}

map<int, vector<int> > aGraph = {
    {1, {2, 3}},
    {2, {1, 4, 5}},
    {3, {1, 6}},
    {4, {2}},
    {5, {2, 6}},
    {6, {3, 5}}
};

我创建了一个名为BFSPaths的函数来解决问题,但是我继续在答案{{1, 2, 3, 6}, {1, 2, 4, 5, 6}}中获得一个额外的数字。我无法弄清楚为什么2和4被添加到答案中。这就是函数的样子:

vector<vector<int>> BFSPaths(map<int, vector<int>> &graph, int head, int tail)
{
    vector<vector<int>> out;
    vector<int> init {head};
    vector<tuple<int, vector<int>>> queue = { make_tuple(head, init) };

    while (queue.size() > 0)
    {
        int vertex = get<0>(queue.at(0));
        vector<int> path = get<1>(queue.at(0));
        queue.erase(queue.begin());

        vector<int> difference;
        sort(graph.at(vertex).begin(), graph.at(vertex).end());
        sort(path.begin(), path.end());

        set_difference(
                graph.at(vertex).begin(), graph.at(vertex).end(),
                path.begin(), path.end(),
                back_inserter( difference )
        );

        for (int v : difference)
        {
            if (v == tail)
            {
                path.push_back(v);
                out.push_back(path);
            }
            else
            {
                path.push_back(v);
                tuple<int, vector<int>> temp (v, path);
                queue.push_back(temp);
            }
        }
    }
    return out;
}

这就是我调用我的函数(打印到shell)的方法:

void testBFSPaths(map<int, vector<int>> &graph, int head, int tail)
{
    vector<vector<int>> paths = BFSPaths(graph, head, tail);

    for (int i=0; i<paths.size(); i++)
    {
        print(paths.at(i));
    }
}

int main ()
{
    // graph definition goes here ....

    testBFSPaths(aGraph, 1, 6);
}

如果有人能给我一个正确的方向,我将不胜感激。

2 个答案:

答案 0 :(得分:1)

据我所知,你在这里计算可到达顶点和当前顶点之间路径的集合差异:

set_difference(
    graph.at(vertex).begin(), graph.at(vertex).end(),
    path.begin(), path.end(),
    back_inserter( difference )
);

但就BFS而言,它没有任何意义。正如您可以进一步看到的那样,无论它们是否位于从头到尾的路径上,您都会将这个差异的顶点添加到您的答案中。 在这种情况下,你应该寻找另一种方法,并稍微改变你的算法。 我建议的步骤:

  1. 像往常一样添加头部顶点,但没有路径。
  2. 提取队列的头部并将所有相邻的顶点添加到队列中,并带有指向其前任的链接。
  3. 重复直到队列不为空或达到尾部。
  4. 通过跟踪前辈的链接,从头到尾获取路径。
  5. 顺便说一句,我建议您在删除队列头时不要使用queue.erase(...)方法(改为使用queue.pop())。此外,您可以将map.at(key)方法更改为简单map[key]

    最后一件事 - 如果你不得不经常对它们进行排序,那么我不清楚为什么要在vector<int>中存储相邻的顶点。使用像set<int>这样的smth,这样你就不用担心了。

答案 1 :(得分:0)

问题是路径正在更新path.insert(path.end(), v)。我需要使用临时路径,以便在迭代期间访问节点不会不必要地更改原始路径。

我也使用了套装(差别不大,它只删除了分拣步骤)。

修复后的功能如下:

vector<set<int>> BFSPaths(map<int, set<int>> &graph, int head, int tail)
{
    vector<set<int>> out;
    set<int> init {head};
    queue<tuple<int, set<int>>> aQueue;
    aQueue.push( make_tuple(head, init) );

    while (aQueue.size() > 0)
    {
        int vertex = get<0>(aQueue.front());
        set<int> path = get<1>(aQueue.front());
        aQueue.pop();

        vector<int> difference;
        set_difference(
            graph[vertex].begin(), graph[vertex].end(),
            path.begin(), path.end(),
            back_inserter( difference )
        );


        for (int v : difference)
        {
            set<int> tempPath;
            tempPath.insert(path.begin(), path.end());
            tempPath.insert(tempPath.end(), v);

            if (v == tail)
            {
                out.push_back(tempPath);
            }
            else
            {
                tuple<int, set<int>> temp (v, tempPath);
                aQueue.push(temp);
            }
        }
    }

    return out;
}

tempPath现在是传递给队列或添加到out向量的内容。