C ++:使用BFS查找矩阵的路径

时间:2014-12-06 02:52:03

标签: c++ graph segmentation-fault

假设有一个矩阵

  

1 1 0 0 0

     

0 1 1 0 0

     

1 0 1 1 0

     

0 1 1 0 0

     

0 0 1 1 1

并要求找到路径仅从左上角(粗体斜体1)到右下角(另一个类似的1)传递 。一旦这样的路径以粗体显示。

我一直在尝试用C ++实现这个,但我很惊讶 - segfaulting。更重要的是,我无法在不重复大量代码的情况下解决任何问题。

这是我的代码:

#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <list>

using namespace std;

typedef pair<int, int> Coords;

struct Point {
    int x, y;
    int val;
    bool visited;
    Point (int a, int b, int v) : x(a), y(b), val(v), visited(false) {}
};

int main() {
    int n;
    cin >> n;

    vector<vector<Point> > pts(n, vector<Point>(n, Point(0, 0, 0)));
    int temp = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            cin >> temp;
            pts[i][j] = Point(i, j, temp);
        }
    }

    queue<Coords> toVisit;

    toVisit.push(Coords(0,0));
    Coords cur(0, 0);
    vector<Coords> neighbors;

    while(!toVisit.empty()) {
        cur = toVisit.back();
        toVisit.pop();
        int x = cur.first, y = cur.second;
        pts[x][y].visited = true;

        bool xgt0 = x > 0, xltm = x < n;
        bool ygt0 = y > 0, yltm = y < n;

        //  x-1,y-1 x  ,y-1 x+1,y-1
        //  x-1,y   x  ,y   x+1,y
        //  x-1,y+1 x  ,y+1 x+1,y+1

        if(xgt0) {
                    if(!pts[x-1][y].visited)   toVisit.push(Coords(x-1,y));
            if(ygt0 && !pts[x-1][y-1].visited) toVisit.push(Coords(x-1,y-1));
            if(yltm && !pts[x-1][y+1].visited) toVisit.push(Coords(x-1,y+1));
        }

        if(ygt0 && !pts[x][y-1].visited) toVisit.push(Coords(x,y-1));
        if(yltm && !pts[x][y+1].visited) toVisit.push(Coords(x,y+1));

        if(xltm) {
                    if(!pts[x+1][y].visited)   toVisit.push(Coords(x+1,y));
            if(ygt0 && !pts[x+1][y-1].visited) toVisit.push(Coords(x+1,y-1));
            if(yltm && !pts[x+1][y+1].visited) toVisit.push(Coords(x+1,y+1));
        }
    }

    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            cout << pts[i][j].visited << " ";
        }
        cout << endl;
    }
}

根本不起作用。我该如何解决这个问题?

如何编写此程序而不在BFS邻居添加段中复制如此多的代码?


修改

解决了,这是代码(现在完全解决了原始问题)。

进行了一些重构以减少代码重复,但可以做更多的事情,例如将if(something && proceed(...)) push(...)转换为if(something) pushIfOK(...)。对于喜欢冒险的读者来说,这只是一个练习,只需要比我现在更多的时间。 :)

#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <list>

using namespace std;

typedef pair<int, int> Coords;

struct Point {
    int x, y;
    bool val; //passable or not?
    bool visited;
    Point (int a, int b, bool v) : x(a), y(b), val(v), visited(false) {}
};

bool proceed(Point);

int main() {
    int n;
    cin >> n;

    vector<vector<Point> > pts(n, vector<Point>(n, Point(0, 0, true)));
    int temp = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            cin >> temp;
            pts[i][j] = Point(i, j, temp == 1);
        }
    }

    queue<Coords> toVisit;

    toVisit.push(Coords(0,0));
    Coords cur(0, 0);
    vector<Coords> neighbors;

    while(!toVisit.empty()) {
        cur = toVisit.back();
        toVisit.pop();
        int x = cur.first, y = cur.second;
        pts[x][y].visited = true;

        bool xgt0 = x > 0, xltm = x < n - 1;
        bool ygt0 = y > 0, yltm = y < n - 1;

        //  x-1,y-1 x  ,y-1 x+1,y-1
        //  x-1,y   x  ,y   x+1,y
        //  x-1,y+1 x  ,y+1 x+1,y+1

        if(ygt0 && proceed(pts[x][y-1])) toVisit.push(Coords(x,y-1));
        if(yltm && proceed(pts[x][y+1])) toVisit.push(Coords(x,y+1));

        if(xgt0) {
            if(proceed(pts[x-1][y])) toVisit.push(Coords(x-1,y));
            if(ygt0 && proceed(pts[x-1][y-1])) toVisit.push(Coords(x-1,y-1));
            if(yltm && proceed(pts[x-1][y+1])) toVisit.push(Coords(x-1,y+1));
        }

        if(xltm) {
            if(proceed(pts[x+1][y])) toVisit.push(Coords(x+1,y));
            if(ygt0 && proceed(pts[x+1][y-1])) toVisit.push(Coords(x+1,y-1));
            if(yltm && proceed(pts[x+1][y+1])) toVisit.push(Coords(x+1,y+1));
        }
    }

    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            cout << pts[i][j].visited << " ";
        }
        cout << endl;
    }
}

bool proceed(Point p) { return p.val && !p.visited; }

1 个答案:

答案 0 :(得分:0)

  

我一直在尝试用C ++实现这个,但我 - 惊讶 - segfaulting。

您的segfaults问题是由于高价值检查:

if (yltm && !pts[x][y+1].visited) toVisit.push(Coords(x,y+1));

请注意,当y = n - 1 yltm == true并且您尝试访问数组中的pts[x][n]条目时,该条目不存在(其位置为n + 1,基于零的索引以及全部)

不幸的是,由于输入数据的性质,您需要检查边界并拥有所有重复的代码,但我不认为在这种情况下您可以避免它。在修复segfaulting并继续尝试找到角落之间的实际路径之后的提示:尝试跟踪搜索的“深度”并使用它来查找从右下角返回到左上角的路径。