一、题意

给出一个比较复杂的道路。每个结点有通行方向的限定。
输入起点、起点方向、终点,要求出最短路径并打印出路径。

二、解析

这是一道比较复杂的bfs题目。最主要是的要找清楚状态点是什么。在本题中,状态点是包含(x, y, dir)的3维点。因此在维护vis数组、父节点p数组、下一步方向的vec数组都需要是3维的。
此外对于向右转、向左转等旋转操作,可以通过一个如代码中getNext()中实现的方法。
然后关于打印路径,只要维护好了p数组,只要在最后写个while循环将p数组中的点链转存到vector中即可,然后就可以逆序打印出路径了。

三、代码

#include <iostream>
#include <string>
#include <queue>
#include <cstring>
using namespace std;
const string direction = "NESW";
const int Fx[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
struct node {
    int x, y, dir;
    node() {}
    node(int x, int y, int dir) : x(x), y(y), dir(dir) {}
} p[15][15][5];
int x0, y0, dir0, xt, yt;
bool vis[15][15][5];
string vec[15][15][5];

void clear() {
    memset(vis, 0, sizeof(vis));
    memset(p, 0, sizeof(p));
    for(int i = 0; i < 15; i ++) {
        for(int j = 0; j < 15; j ++) {
            for(int k = 0; k < 5; k ++) vec[i][j][k].clear();
        }
    }
}

node getNext(const node& u, char ch) {
    int dir;
    if(ch == 'F') dir = u.dir;
    else if(ch == 'R') dir = (u.dir + 1) % 4;
    else dir = (u.dir + 3) % 4;
    return node(u.x + Fx[dir][0], u.y + Fx[dir][1], dir);
}

void bfs(int x, int y, int dir) {
    queue<node> que;
    que.push(node(x, y, dir));
    vis[x][y][dir] = 1;
    p[x][y][dir] = node(-1, -1, -1);
    bool ok = 0;
    int dirt;
    while(!que.empty()) {
        node u = que.front();
        que.pop();
        if(u.x == xt && u.y == yt) {
            ok = 1, dirt = u.dir;
            break;
        }
        for(auto ch : vec[u.x][u.y][u.dir]) {
            node v = getNext(u, ch);
            // cout << "("<<u.x<<", "<<u.y<<", "<<direction[u.dir]<<") --> ch == "<<ch 
            // << "--> ("<<v.x<<", "<<v.y<<", "<<direction[v.dir]<<") "<<endl;
            if(vis[v.x][v.y][v.dir]) continue;
            que.push(v);
            vis[u.x][u.y][u.dir] = 1;
            p[v.x][v.y][v.dir] = u;
        }
    }
    if(!ok) cout << "  No Solution Possible" << endl;
    else {
        vector<node> tmp;
        int x = xt, y = yt, dir = dirt;
        do {
            tmp.push_back(node(x, y, dir));
            node next = p[x][y][dir];
            x = next.x, y = next.y, dir = next.dir;
        } while(x != -1);
        tmp.push_back(node(x0, y0, dir0));
        for(int i = tmp.size() - 1, cnt = 0; i >= 0; i --) {
            if(cnt == 0) cout << " ";
            node & cur = tmp[i];
            cout << " (" << cur.x << "," << cur.y << ")";
            cnt ++;
            if(i == 0) cout << endl;
            else if(cnt == 10) cout << endl, cnt = 0;
        }
    }
}

int main() {
    string name;
    while(cin >> name && name != "END") {
        clear();
        char ch0;
        cin >> x0 >> y0 >> ch0 >> xt >> yt;
        dir0 = direction.find(ch0);
        int x, y;
        string str;
        while(cin >> x && x) {
            cin >> y;
            while(cin >> str && str != "*") {
                int dir = direction.find(str[0]);
                vec[x][y][dir] = str.substr(1);
            }
        }
        cout << name << endl;
        bfs(x0 + Fx[dir0][0], y0 + Fx[dir0][1], dir0);
    }
}

四、归纳

  • bfs问题要先想清楚“状态点”如何定义,然后维护相应维度的vis、vec数组。
  • 如果需要打印路径需要用p数组进行父节点的存储。
  • debug时不要太着急,可以将打印信息写的详细一点,这样才能有利于更快地发现问题!就像代码中注释部分所示,花不了多长时间的。