一、题意
给出一个比较复杂的道路。每个结点有通行方向的限定。
输入起点、起点方向、终点,要求出最短路径并打印出路径。
二、解析
这是一道比较复杂的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时不要太着急,可以将打印信息写的详细一点,这样才能有利于更快地发现问题!就像代码中注释部分所示,花不了多长时间的。

京公网安备 11010502036488号