P1825 [USACO11OPEN]Corn Maze S
P1825 [USACO11OPEN]Corn Maze S
标记还是不标记?这是个问题.
直接看得出来是bfs,只不过遇到传送装置要特殊处理.
最初的想法是,每当遍历到一个为传送门的新格子时,而该格子本身不标记,将该格子传送到的格子标记为visited.在这个基础上就可以当作普通bfs来做了.
结果是WA和AC参半.这样做的漏洞在于使得一个传送装置只能单向传送一次,而这是会漏解的,如:
#####.# #@A=#A# #######
→↑↓→即可到达终点,而上述做法导致此情况无解.
正确的方法是遇到传送装置时标记该格子,而不标记传送到的格子.在这个基础上当成普通bfs即可AC,
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; int n, m, sx, sy, fx, fy; int trans[30][2][2]; int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0}; char s[310][310]; bool vis[310][310]; struct S { int x, y, t; }; queue<struct S> que; int main() { // freopen("out.txt", "w", stdout); // freopen("in.txt", "r", stdin); char tmp; cin >> n >> m; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) { cin >> tmp; if (tmp == '@') { sx = i; sy = j; } else if (tmp == '=') { fx = i; fy = j; } else if (tmp != '#' && tmp != '.') { if (!trans[tmp - 'A'][0][0]) { trans[tmp - 'A'][0][0] = i; trans[tmp - 'A'][0][1] = j; } else { trans[tmp - 'A'][1][0] = i; trans[tmp - 'A'][1][1] = j; } } s[i][j] = tmp; } que.push({sx, sy, 0}); vis[sx][sy] = true; while (!que.empty()) { struct S p = que.front(); que.pop(); if (p.x == fx && p.y == fy) { printf("%d\n", p.t); break; } for (int i = 0; i < 4; i++) { int nx = p.x + dx[i], ny = p.y + dy[i]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && s[nx][ny] != '#' && !vis[nx][ny]) { if (s[nx][ny] == '.' || s[nx][ny] == '=') { que.push({nx, ny, p.t + 1}); // printf("!!!(%d,%d) %d\n", nx, ny, p.t + 1); vis[nx][ny] = true; } else { // transport vis[nx][ny] = true; int ind = s[nx][ny] - 'A'; if (trans[ind][0][0] == nx && trans[ind][0][1] == ny) { nx = trans[ind][1][0]; ny = trans[ind][1][1]; } else { nx = trans[ind][0][0]; ny = trans[ind][0][1]; } // if (!vis[nx][ny]) { que.push({nx, ny, p.t + 1}); // printf("!!!(%d,%d) %d\n", nx, ny, p.t + 1); // vis[nx][ny] = true; // } } } } } return 0; }
此外,实践表明如果遇到传送门时不对任何格子做标记,也不检测目标格子是否已经标记而直接push到队列里面的话仍然可以AC.此时可以想象到队列里面有几个点传送来传送去,他们的step不断递增并且不会跳出这个循环,并不会对结果产生影响,只是让搜索的效率有所下降,这样的点越多效率损耗越大.
这道题最多只有26个传送门,所以照常AC了.
所以说如果实在不确定(懒得想)标记与否,可以牺牲一点效率换取稳定性.