胖胖的牛牛(优先队列BFS)

思路

  • 优先队列BFS, 按照起点到每个点的转弯次数从小到大排序
  • 每次取出队头元素, 令st[x][y] = true;,代表每次出队的元素的转弯次数已经确定
  • 每次入队的点的转弯次数未必是最少的, 可能从别的路径走到该点的转弯次数更少, 所以入队的时候不要令st[a][b] = true

代码

#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;
}