1. 程式人生 > 實用技巧 >window.location.href

window.location.href

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; }
View Code

此外,實踐表明如果遇到傳送門時不對任何格子做標記,也不檢測目標格子是否已經標記而直接push到佇列裡面的話仍然可以AC.此時可以想象到佇列裡面有幾個點傳送來傳送去,他們的step不斷遞增並且不會跳出這個迴圈,並不會對結果產生影響,只是讓搜尋的效率有所下降,這樣的點越多效率損耗越大.

這道題最多隻有26個傳送門,所以照常AC了.

所以說如果實在不確定(懶得想)標記與否,可以犧牲一點效率換取穩定性.