题目描述
输入格式
输出格式
题意翻译
给出一个箭头迷宫,在每个路口处,如果你从某个方向进入了该路口,那么路口的地面上在靠近你的方向会画有一组箭头,它们相对于你的方向可以是向左,向前,向右,或者是它们的任意组合。
当你从某一方向进入某个入口时,下一步只能在这个入口对应方向上标记的箭头中选一个方向继续行进。在起点时,可以选择任何方向。
给出起点和终点,求它们之间的最短路径。
每条边的长度为1
输入输出样例
输入
SAMPLE 3 1 N 3 3 1 1 WL NR * 1 2 WLF NR ER * 1 3 NL ER * 2 1 SL WR NF * 2 2 SL WF ELF * 2 3 SFR EL * 0 NOSOLUTION 3 1 N 3 2 1 1 WL NR * 1 2 NL ER * 2 1 SL WR NFR * 2 2 SR EL * 0 END Figure 1: An Example Walk-Through Arrow Maz
输出
SAMPLE (3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1) (2,2) (1,2) (1,3) (2,3) (3,3) NOSOLUTION No Solution Possible
代码
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int N = 10;
int d[N][N][4];
bool has_edge[N][N][4][4];//当前状态是(r, c, dir) 是否可以沿着转弯方向turn 行走
const char *dirs = "NESW";//方向
const char *turns = "FLR";//转向
int r1, c1, dir, r2, c2, r0, c0;
//将4个方向和3种转弯方式编号为0~3和0~2
int dir_id(char c){return strchr(dirs, c) - dirs;}
int turn_id(char c){return strchr(turns, c) - turns;}
struct Node
{
int r, c, dir;
Node(int r, int c, int dir):r(r), c(c), dir(dir){}
Node(){}
};
Node p[N][N][4];//距离 父节点
int dr[] = {-1, 0, 1, 0};
int dc[] = {0, 1, 0, -1};
Node walk(const Node& u, int turn)//直走 左转 右转
{
int dir = u.dir;
if(turn == 1) dir = (dir + 3) % 4;//左
if(turn == 2) dir = (dir + 1) % 4;//右
return Node(u.r + dr[dir], u.c + dc[dir], dir);
}
bool inside(int r, int c)
{
return r >= 1 && r <= 9 && c >= 1 && c <= 9;
}
void print_ans(Node u)
{
//从目标结点逆序追溯到初始结点
vector<Node> nodes;
for(;;)
{
nodes.push_back(u);
if(d[u.r][u.c][u.dir] == 0) break;
u = p[u.r][u.c][u.dir];
}
nodes.push_back(Node(r0, c0, dir));
//打印解 每行10个
int cnt = 0;
for(int i = nodes.size() - 1; i >= 0; i --)
{
if(cnt % 10 == 0) cout << ' ';
cout << ' ' << '(' << nodes[i].r << ',' << nodes[i].c << ')';
if(++ cnt % 10 == 0) cout << endl;
}
if(nodes.size() % 10 != 0) cout << endl;
}
void solve()
{
queue<Node> q;
memset(d, -1, sizeof d);
Node u(r1, c1, dir);
d[r1][c1][dir] = 0;
q.push(u);
while(!q.empty())
{
auto u = q.front(); q.pop();
if(u.r == r2 && u.c == c2){print_ans(u); return ;}
for(int i = 0; i < 3; i ++)
{
auto v = walk(u, i);
//能走到 + 在里面 + 没被遍历过
if(has_edge[u.r][u.c][u.dir][i] && inside(v.r, v.c) && d[v.r][v.c][v.dir] < 0)
{
d[v.r][v.c][v.dir] = d[u.r][u.c][u.dir] + 1;
p[v.r][v.c][v.dir] = u;
q.push(v);
}
}
}
//顶头两个空格
cout << " No Solution Possible" << endl;
}
string maze;
bool input()
{
cin >> maze;
if(maze == "END") return false;
memset(has_edge, 0, sizeof has_edge);
char op;
cin >> r0 >> c0 >> op >> r2 >> c2;
dir = dir_id(op);
r1 = r0 + dr[dir];
c1 = c0 + dc[dir];
//读入各个边
int r, c;
string tmp;
while(cin >> r, r)
{
cin >> c;
while(cin >> tmp, tmp != "*")
{
for(int i = 1; i < tmp.size(); i ++)
has_edge[r][c][dir_id(tmp[0])][turn_id(tmp[i])] = true;
}
}
return true;
}
int main()
{
while(input())
{
cout << maze << endl;
solve();
}
return 0;
}