Question

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. 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);

Was it helpful?

Solution 2

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; 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). The [2][1] and [0][2] dead-ends account for the other two. Basically, you need to decrement result when you follow a dead-end and reach the end.

Designating end point

Bounds checking changed after seeing answer by 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

OTHER TIPS

The code as given produces 10. With a few modifications, here is a live example. 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. A second modification is that range checking now takes place before pushing into the queue, so the while loop is modified as follows:

    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.

Most importanly, if your goal is to find the shortest path through this map, then this algorithm is not appropriate. Number 10 is the number of all positions that can be visited starting from (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.

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. And your queue will have to be replaced by a priority queue, such that points are visited by increasing distance.

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). 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.

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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top