简体   繁体   English

BFS实施无法正常工作

[英]BFS Implementation not working properly

Here is my BFS implementation which is returning me always 0. I should basically find the shortest path through this map, 1 - means it's a wall, 0 - means no wall. 这是我的BFS实现,总是返回0。我基本上应该找到通过此地图的最短路径,1-表示它是一堵墙,0-表示没有墙。 Where i'm mistaking? 我在哪里误会?

class node { public: int x,y; };

int bfs(int x, int y)
{
    node start;
    int result = 0;
    start.x = 0;
    start.y = 0;
    std::queue<node> search_queue;
    bool visited[4][4];
    int map[4][4] = {
                    {0,1,0,1},
                    {0,0,0,0},
                    {1,0,1,0},
                    {0,1,0,0}
                };
    for(int i = 0 ; i < 4; i ++)
    {
        for(int j = 0 ; j < 4; j++)
        {
            visited[i][j] = false;
        }
    }
    search_queue.push(start);
    while(!search_queue.empty())
    {
        node top = search_queue.front();
        search_queue.pop();

        if (visited[top.x][top.y]) continue;
        if (map[top.x][top.y] == 1) continue;
            if (top.x < 0 || top.x >= 4) continue;
            if (top.y < 0 || top.y >= 4) continue;
        visited[top.x][top.y] = true;
        result++;
        node temp;

        temp.x = top.x+1;
        temp.y=top.y;
        search_queue.push(temp);

        temp.x = top.x-1;
        temp.y=top.y;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y=top.y+1;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y=top.y-1;
        search_queue.push(temp);
    }
    return result;
}

and i call it from main like that : cout<<bfs(0,0); 我像这样从main调用它: cout<<bfs(0,0);

The code as given produces 10. With a few modifications, here is a live example . 给出的代码产生10。经过一些修改,这是一个在线示例 One modification is that input x , y is set as the start point, I guess this was the intent as pointed out by Jonathan Leffler above. 一种修改是将输入xy设置为起点,我想这就是上面Jonathan Leffler指出的意图。 A second modification is that range checking now takes place before pushing into the queue, so the while loop is modified as follows: 第二个修改是范围检查现在推入队列之前进行 ,因此while循环修改如下:

    while(!search_queue.empty())
    {
        node top = search_queue.front();
        search_queue.pop();

        if (visited[top.x][top.y]) continue;
        if (map[top.x][top.y] == 1) continue;
        visited[top.x][top.y] = true;
        result++;
        node temp;

        temp.y = top.y;

        if (top.x < 3)
        {
            temp.x = top.x + 1;
            search_queue.push(temp);
        }

        if (top.x > 0)
        {
            temp.x = top.x - 1;
            search_queue.push(temp);
        }

        temp.x = top.x;

        if (top.y < 3)
        {
            temp.y = top.y + 1;
            search_queue.push(temp);
        }

        if (top.y > 0)
        {
            temp.y = top.y - 1;
            search_queue.push(temp);
        }
    }

Now, assuming that the start point is within range (and you may add another check for that), this loop will always move within range and it will never put out-of-range point into the queue, saving a number of computations. 现在,假设起点在范围内(并且您可以为此添加其他检查),则此循环将始终在范围内移动,并且永远不会将超出范围的点放入队列中,从而节省了大量计算。

Also, as your conditions are initially written, you access arrays visited and map before range checking, which may have bad results. 此外,由于你的条件最初写的,您可以访问阵列visitedmap范围检查,这可能会导致糟糕的结果

Most importanly, if your goal is to find the shortest path through this map , then this algorithm is not appropriate. 最重要的是,如果您的目标是find the shortest path through this map ,则此算法不合适。 Number 10 is the number of all positions that can be visited starting from (0, 0). 数字10是从(0,0)开始可以访问的所有位置的数字。 It is not the shortest path to anywhere. 这不是通往任何地方的最短路径。 What you need is a shortest path algorithm, and since graph weights are positive here, a simple option is Dijsktra's algorithm . 您需要的是最短路径算法,并且由于图权在这里是正数,因此Dijsktra的算法是一个简单的选择。

This requires only a few modifications to your code, but I leave this to you. 这只需要对您的代码进行一些修改,但是我留给您。 Basically you will need to replace array visited by an integer array distance designating the minimum distance to every point from the start position, initialized to "infinity" and only decreasing. 基本上,您将需要用整数数组distance替换visited的数组,该整数数组distance指定从起始位置到每个点的最小距离,并初始化为“无穷大”并且仅减小。 And your queue will have to be replaced by a priority queue, such that points are visited by increasing distance. 而且您的队列将必须替换为优先级队列,以便通过增加距离来访问点。

Instrumenting path 检测路径

#include <iostream>
#include <queue>

class node { public: int x, y; };

int bfs(int x, int y)
{
    node start;
    int result = 0;
    start.x = x;
    start.y = y;
    std::queue<node> search_queue;
    bool visited[4][4];
    int map[4][4] =
    {
        {0, 1, 0, 1},
        {0, 0, 0, 0},
        {1, 0, 1, 0},
        {0, 1, 0, 0}
    };
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            visited[i][j] = false;
        }
    }
    search_queue.push(start);
    while (!search_queue.empty())
    {
        node top = search_queue.front();
        search_queue.pop();

        if (visited[top.x][top.y])
            continue;
        if (map[top.x][top.y] == 1)
            continue;
        if (top.x < 0 || top.x >= 4)
            continue;
        if (top.y < 0 || top.y >= 4)
            continue;

        visited[top.x][top.y] = true;
        std::cout << "visit: [" << top.x << "][" << top.y << "]\n";
        result++;
        node temp;

        temp.x = top.x + 1;
        temp.y = top.y;
        search_queue.push(temp);

        temp.x = top.x - 1;
        temp.y = top.y;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y = top.y + 1;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y = top.y - 1;
        search_queue.push(temp);
    }
    return result;
}

int main()
{
    std::cout << bfs(0, 0);
}

produces: 生产:

visit: [0][0]
visit: [1][0]
visit: [1][1]
visit: [2][1]
visit: [1][2]
visit: [0][2]
visit: [1][3]
visit: [2][3]
visit: [3][3]
visit: [3][2]
10

One interesting point is that it reaches [3][3] and continues; 有趣的一点是它达到[3][3]并持续下去; you don't seem to have the end well defined. 您似乎没有明确定义目标。 That accounts for one of the extra count (compared with the 7 that should be expected). 这占了额外的计数之一(与预期的7相比)。 The [2][1] and [0][2] dead-ends account for the other two. [2][1][0][2]死角占了另外两个。 Basically, you need to decrement result when you follow a dead-end and reach the end. 基本上,当您走到尽头并到达终点时,您需要减少result

Designating end point 指定终点

Bounds checking changed after seeing answer by iavr . 看到iavr的 答案后,边界检查发生了变化

#include <iostream>
#include <queue>

class node { public: int x, y; };

int bfs(int bx, int by, int ex, int ey)
{
    node start;
    int result = 0;
    start.x = bx;
    start.y = by;
    std::queue<node> search_queue;
    bool visited[4][4];
    int map[4][4] =
    {
        {0, 1, 0, 1},
        {0, 0, 0, 0},
        {1, 0, 1, 0},
        {0, 1, 0, 0}
    };
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            visited[i][j] = false;
        }
    }
    search_queue.push(start);
    while (!search_queue.empty())
    {
        node top = search_queue.front();
        search_queue.pop();

        if (top.x < 0 || top.x >= 4)
            continue;
        if (top.y < 0 || top.y >= 4)
            continue;
        if (visited[top.x][top.y])
            continue;
        if (map[top.x][top.y] == 1)
            continue;

        visited[top.x][top.y] = true;
        std::cout << "visit: [" << top.x << "][" << top.y << "]\n";
        result++;

        if (top.x == ex && top.y == ey)
            break;

        node temp;

        temp.x = top.x + 1;
        temp.y = top.y;
        search_queue.push(temp);

        temp.x = top.x - 1;
        temp.y = top.y;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y = top.y + 1;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y = top.y - 1;
        search_queue.push(temp);
    }
    return result;
}

int main()
{
    std::cout << bfs(0, 0, 3, 3);
}

Output: 输出:

visit: [0][0]
visit: [1][0]
visit: [1][1]
visit: [2][1]
visit: [1][2]
visit: [0][2]
visit: [1][3]
visit: [2][3]
visit: [3][3]
9

Getting the correct answer 得到正确的答案

#include <iostream>
#include <queue>

class node { public: int x, y, l; };

int bfs(int bx, int by, int ex, int ey)
{
    node start;
    int result = 0;
    start.x = bx;
    start.y = by;
    start.l = 1;
    std::queue<node> search_queue;
    bool visited[4][4];
    int map[4][4] =
    {
        {0, 1, 0, 1},
        {0, 0, 0, 0},
        {1, 0, 1, 0},
        {0, 1, 0, 0}
    };
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            visited[i][j] = false;
        }
    }
    search_queue.push(start);
    while (!search_queue.empty())
    {
        node top = search_queue.front();
        search_queue.pop();

        if (visited[top.x][top.y])
            continue;
        if (map[top.x][top.y] == 1)
            continue;
        if (top.x < 0 || top.x >= 4)
            continue;
        if (top.y < 0 || top.y >= 4)
            continue;

        visited[top.x][top.y] = true;
        std::cout << "visit: [" << top.x << "][" << top.y << "] = " << top.l << "\n";

        result = top.l;
        if (top.x == ex && top.y == ey)
            break;

        node temp;

        temp.l = top.l + 1;

        temp.x = top.x + 1;
        temp.y = top.y;
        search_queue.push(temp);

        temp.x = top.x - 1;
        temp.y = top.y;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y = top.y + 1;
        search_queue.push(temp);

        temp.x = top.x;
        temp.y = top.y - 1;
        search_queue.push(temp);
    }
    return result;
}

int main()
{
    std::cout << bfs(0, 0, 3, 3) << std::endl;
}

Output: 输出:

visit: [0][0] = 1
visit: [1][0] = 2
visit: [1][1] = 3
visit: [2][1] = 4
visit: [1][2] = 4
visit: [0][2] = 5
visit: [1][3] = 5
visit: [2][3] = 6
visit: [3][3] = 7
7

Your code just counts the number of accessible cells. 您的代码仅计算可访问单元的数量。 I assume you want to count only the cells between start and end (the result variable is useless in this context). 我假设您只想计算开始和结束之间的单元格( result变量在这种情况下是无用的)。 I usually use a data structure like this: 我通常使用这样的数据结构:

std::queue<pair<node,int> > search_queue;

When you extract an element from the queue, code looks like this: 从队列中提取元素时,代码如下所示:

    node top = search_queue.front().first;
    int current_length = search_queue.front().second;
    // if (top == end) return current_length;  (this is the value you are interested in)

Adding the next elements to the queue would of course, look like this: 当然,将下一个元素添加到队列中将如下所示:

    search_queue.add(make_pair(temp, current_length + 1));

I hope the full code is easy to get from here. 我希望完整的代码可以从这里轻松获得。

I think you have to debug the assignment result of the class "node". 我认为您必须调试“节点”类的分配结果。 It's probably not working. 可能不起作用。

To do so you can overload the operator "=" and add a default constructor with a reference argument of type "node". 为此,您可以重载运算符“ =”并添加一个默认构造函数,其引用参数类型为“ node”。

another method 另一种方法

class Queue:
    def __init__(self):
            self.items=[]
    def enqueue(self,item):
            self.items.append(item)
    def dequeue(self):
            return self.items.pop(0)
    def isEmpty(self):
            return self.items==[]
    def size(self):
            return len(self.items)

class Vertex:
    def __init__(self,id):
            self.id=id
            self.color="white"
            self.dist=None
            self.pred=None
            self.sTime=0
            self.fTime=0
            self.connectedTo={}

    def addNeighbor(self,nbr,weight):
            self.connectedTo[nbr]=weight
    def __str__(self):
            return str(self.id)+"connectedTo"+str([x for x in self.connectedTo])
    def getConnection(self):
            return self.connectedTo.keys()
    def getId(self):
            return self.id
    def getWeight(self,nbr):
            return self.connectedTo[nbr]
    def setColor(self,c):
            self.color=c
    def getColor(self):
            return self.color
    def setDistance(self,d):
            self.dist=d
    def getDistance(self):
            return self.dist
    def setPred(self,u):
            self.pred=u
    def getPred(self):
            return self.pred
    def getsTime(self):
            return self.sTime
    def getfTime(self):
            return self.fTime
    def setsTime(self,t):
            self.sTime=t
    def setfTime(self,t):
            self.fTime=t

class Graph:
    def __init__(self):
            self.vertList={}
            self.numVertices=0
            self.time=0
    def addVertex(self,id):
            self.numVertices=self.numVertices+1
            newVertex=Vertex(id)
            self.vertList[id]=newVertex
    def getVertex(self,id):
            if id in self.vertList:
                    return self.vertList[id]
            else:
                    return None
    def __contains__(self,id):
            return id in self.vertList
    def addEdge(self,u,v,weight=0):
            if u not in self.vertList:
                    self.addVertex(u)
            if v not in self.vertList:
                    self.addVertex(v)
            self.vertList[u].addNeighbor(self.vertList[v],weight)
    def getVertices(self):
            return self.vertList.keys()
    def __iter__(self):
            return iter(self.vertList.values())
    def bfs(self,start):
            self.vertList[start].setDistance(0)
            self.vertList[start].setColor("gray")
            q=Queue()
            q.enqueue(self.vertList[start])
            while(q.size()>0):
                    u=q.dequeue()
                    u.setColor("black")
                    for v in u.connectedTo:
                            if v.getColor()=="white":
                                    v.setColor("gray")
                                    v.setDistance(u.getDistance()+1)
                                    v.setPred(u)
                                    q.enqueue(v)

                    print"Id ",u.getId()," color ",u.getColor()," Distance ",u.getDistance()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM