【传送门】http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4020
【题目大意】从起点(sx, sy)出发,要到达(ex , ey)。每次从点(x,y)走的时候要看红绿灯,灯的状态为1时只能左右走,走到(x , y+1)或者 (x , y-1);灯为0的时候只能上下走,走到(x +1, y)或者 (x-1 , y)。现在问能不能从源点走到终点,如果能,输出最少需要走多少步。
注意(x,y)代表第x行第y列,不是传统意义上的坐标系。
【题解】求最短路一般用BFS,但是与一般的图不同,这里灯的状态是不断变化的,所以允许走的方向也不同。不妨记一个步数t, t % 2 == 1或者0时方向不同,需要入队的点也不同。
另外有这样一个事实,只要访问过的点,或者说之前已经入过队的点以后都不会再入队,证明如下:
若过之前经过一个点(x0, y0), 经过若干步骤以后,又回到了(x0, y0),那么经过了多少步呢?把沿途所有点相连,必然构成一个长方形或者一条来回的直线,很显然,他们的周长必然是2的倍数,也就是偶数,因此再到这一点时这个灯的状态和上一次经过时是一样的,所以没有任何意义。当然也可能发生了这样一个情况:主人公会在这个矩形中循环走动或者在这条线段来回走动,均无法到达终点。
【代码】
#include <iostream> #include <cstring> #include <string> #include <queue> #include <vector> using namespace std; struct Node { //点的坐标 走过的步数 int x, y, step; }; int dic1[4] = { 1,-1,0,0 }; int dic2[4] = { 0,0,-1,1 }; vector<vector<int> >maps; vector<vector<bool> >vis; int sx, sy, ex, ey; int state; int n, m; //判断点是否能够入队 bool judge(int x, int y) { if (x > 0 && x <= n && y> 0 && y <= m && vis[x][y] == 0) { return true; } return false; } //BFS求最短路 int bfs(Node s) { queue <Node> Q; Q.push(s); Node p, q; vis[s.x][s.y] = true; while (!Q.empty()) { p = Q.front(); Q.pop(); //如果已经到达终点就直接返回步数即可 if (p.x == ex && p.y == ey) { return p.step; } state = maps[p.x][p.y]; //看看走到这一点共走了多少步,奇数步需要反转灯的状态,偶数步相当于不用反转 if ((p.step) % 2 == 1) { if (state == 1) { state = 0; } else { state = 1; } } //看这一点的状态(0,1) 确定能走到那两个点,将能到达的点入队 if (state == 0) { for (int i = 0; i<2; i++) { q.x = p.x + dic1[i]; q.y = p.y + dic2[i]; if (judge(q.x, q.y) == true) { vis[q.x][q.y] = true; q.step = p.step+1; Q.push(q); } } } else if (state == 1) { for (int i = 2; i<4; i++) { q.x = p.x + dic1[i]; q.y = p.y + dic2[i]; if (judge(q.x, q.y) == true) { vis[q.x][q.y] = true; q.step = p.step + 1; Q.push(q); } } } } return -1; } int main() { ios::sync_with_stdio(false); int cas; cin >> cas; while (cas--) { cin >> n >> m; maps.clear(); vis.clear(); maps.resize(n + 1); vis.resize(n + 1); for (int i = 1; i <= n; i++) { maps[i].resize(m + 1); vis[i].resize(m + 1); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> maps[i][j]; } } cin >> sx >> sy >> ex >> ey; if (sx == ex && sy == ey) { cout << 0 << endl; continue; } Node t; t.x = sx; t.y = sy; t.step = 0; state = maps[sx][sy]; int ans = bfs(t); cout << ans << endl; } return 0; }