uva_816 Abbott's Revenge(BFS求解最短路、结点状态由坐标和方向表示)
有点难以置信,写得最久的一道题竟然一遍AC。
分析:
1. 这是给定起点、终点的图的最短路问题。并且并无特殊之处,首选BFS。
2. 唯一的特殊之处在于图中结点并非简单地由坐标构成,还有方向。因此,结点(或者说状态)为三元组:(r, c, direction);
3. 图主要有两种存储方式:邻接表和邻接矩阵。这种显式的、迷宫型的图,首选邻接矩阵。
用bool has_edge[r][c][dir][turn]存储结点之间的关系,含义为:结点(r, c, dir)是否能以turn这种拐弯方式到达另一个结点。
(当然也可以用邻接表 vector<Node> next_node[r][c][dir]) //等等....貌似这不是邻接表,邻接表存储的是边...
4. 标记结点访问情况的三维数组 bool vis[r][c][dir]。注意:如果题目需要路径长度的情况,可以用int d[r][c][dir],当其为-1时标识不可达。
5. 如何根据当前的dir和turn给出下一步的方向。当然可以依次判断。但是,要记住一个原则:将实际含义抽象化、数字化,并找到其中的规律,从而找到简单的表示方式。
char *dirs = "NESW"; char *turns = "FLR"; int ID_dir(char c){return strchr(dirs, c) - dirs;} int ID_turn(char c){return strchr(turns, c) - turns;} int dr[] = {-1, 0, 1, 0}; //与dirs = "NESW"的顺序一致,即顺时针。 int dc[] = {0, 1, 0, -1}; int getDir(int turn, int dir) { if(turn == 0) return dir; if(turn == 1){ return (dir + 3)%4; } if(turn == 2
){ return (dir + 1)%4; } }
#include<bits/stdc++.h> using namespace std; const int maxn = 9 + 3; const int maxs = 20 + 3; string kase; char *dirs = "NESW"; char *turns = "FLR"; int ID_dir(char c){return strchr(dirs, c) - dirs;} int ID_turn(char c){return strchr(turns, c) - turns;} int dr[] = {-1, 0, 1, 0}; //与dirs = "NESW"的顺序一致,即顺时针。 int dc[] = {0, 1, 0, -1}; int getDir(int turn, int dir) { if(turn == 0) return dir; if(turn == 1){ return (dir + 3)%4; } if(turn == 2){ return (dir + 1)%4; } } struct Node{ int r, c; int direction; Node(int r = 0, int c = 0, int dir = 0):r(r), c(c), direction(dir){} }; bool inside(const Node& node, int dir) { int rr = node.r + dr[dir]; int cc = node.c + dc[dir]; return rr >= 0 && rr <= 9 && cc >= 0 && cc <= 9; } Node walk(const Node& node, int dir) { int rr = node.r + dr[dir]; int cc = node.c + dc[dir]; return Node(rr, cc, dir); } Node entrance, goal; Node node0; /* node state: (coordinate, direction) bool has_edge[r][c][dir][turn] represents whether it's valid to turn with certain turning when on (r, c) */ //int d[maxn][maxn][4]; bool has_edge[maxn][maxn][4][3]; //or the structure of the graph is matrix, has_edge is actually describe the graph. void readData() { while(true){ int r, c; string t; cin >> r; if(r == 0) return; cin >> c; while(cin >> t){ if(t == "*"){ break; } int dir = ID_dir(t[0]); for(int i = 1; i < t.size(); i++){ has_edge[r][c][dir][ID_turn(t[i])] = true; } } } } Node p[maxn][maxn][4]; bool vis[maxn][maxn][4]; void print_ans(Node u) { vector<Node>ans; while(1){ ans.push_back(u); u = p[u.r][u.c][u.direction]; if(u.r == 0){ break; } } cout << kase << endl << " "; ans.push_back(entrance); for(int i = ans.size() - 1, cnt = 1; i >= 0; i--, cnt++){ printf("(%d,%d)", ans[i].r, ans[i].c); if(i == 0){ cout << endl; return ; } if(cnt % 10 == 0){ cout << endl << " "; } else cout << " "; } } void solve() { queue<Node>q; q.push(node0); p[node0.r][node0.c][node0.direction] = Node(); while(!q.empty()){ Node u = q.front(); q.pop(); if(u.r == goal.r && u.c == goal.c){ print_ans(u); return; } for(int i = 0; i < 3; i++){//try 3 probable turning int dir = getDir(i, u.direction); if(inside(u, dir) && has_edge[u.r][u.c][u.direction][i]){ Node v = walk(u, dir); if(vis[v.r][v.c][v.direction]){ continue; } p[v.r][v.c][v.direction] = u; vis[v.r][v.c][v.direction] = true; q.push(v); } } } cout << kase << endl << " "; cout << "No Solution Possible" << endl; } int main() { while(cin >> kase && kase != "END"){ string t; cin >> entrance.r >> entrance.c >> t >> goal.r >> goal.c; node0 = walk(entrance, ID_dir(t[0])); memset(has_edge, 0, sizeof(has_edge)); // memset(vis, 0, sizeof(vis)); readData(); solve(); } return 0; }