1020 胖胖的牛牛 优先队列 bfs 转向时上上次xy与当前xy都不同
链接:https://ac.nowcoder.com/acm/problem/208246
来源:牛客网
题目描述
每逢佳节胖三斤,牛牛在过去的节日里长胖了,连拐弯都困难,甚至会卡在门上,所以他很讨厌拐弯。给你一个N*N(2≤N≤100)的方格中,‘x’表示障碍,‘.’表示没有障碍(可以走),牛牛可以从一个格子走到他相邻的四个格子,但是不能走出这些格子。问牛牛从A点到B点最少需要转90度的弯几次。
输入描述:
第一行一个整数:N,下面N 行,每行N 个字符,只出现字符:‘.’,‘x’,‘A’,‘B’;表示上面所说的矩阵格子,每个字符后有一个空格。
输出描述:
一个整数:最少转弯次数。如果不能到达,输出-1。
备注:
开始和结束时的方向任意。
分析
优先队列+bfs。优先处理转向次数最少的。
转向时,和上上次的位置的x和y都不一样。距离+1
走过的点不用再走了。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<double, double> PDD; int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, -1, 1}; const double eps = 1e-6; const int N = 100 + 10; char g[N][N]; int n, m; bool st[N][N]; struct Node { int x, y; int prex, prey; int dis; // 转弯次数 bool operator<(const Node &w) const // 优先队列中按照转弯次数从小到大排列 { return dis > w.dis; } }; int bfs() { int sx, sy, ex, ey; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (g[i][j] == 'A') sx = i, sy = j; if (g[i][j] == 'B') ex = i, ey = j; } } priority_queue<Node> q; q.push({sx, sy, sx, sy, 0}); // 起点的上一个点定义为起点自己 st[sx][sy] = true; // (sx,sy)的最少转弯次数已经确定 while (!q.empty()) { Node t = q.top(); q.pop(); int x = t.x, y = t.y; if (x == ex && y == ey) return t.dis; // 每次出队的元素的转弯次数已经确定 st[x][y] = true; for (int i = 0; i < 4; i++) { int a = x + dx[i], b = y + dy[i]; if (a < 0 || a > n - 1 || b < 0 || b > n - 1) continue; if (g[a][b] == 'x') continue; if (st[a][b]) continue; int add = 0; if (t.prex != a && t.prey != b) // 转弯了 add++; // 每次入队的点的转弯次数未必是最少的, 可能从别的路径走到该点的转弯次数更少, 所以入队的时候不要令st[a][b] = true q.push({a, b, x, y, t.dis + add}); } } return -1; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> g[i][j]; } } cout << bfs() << '\n'; return 0; }