题意

  • n*n的正方形地图,从起点走到终点,图中有一些障碍物不能走
  • 求最小转弯次数

思路

  • 图不大,迷宫问题,考虑搜索,不再记录步长,而是在走每一步的时候考虑和走过来的方向是否相同,如果不同就给转弯次数+1
  • 用一个优先队列避免重复走
  • 不开vis,否则部分优势可能掩盖全局劣势
  • 也可以最短路做,每个点转化成四个点,和其它点建边

代码

#include<bits/stdc++.h>
using namespace std;
//太痛了,01bfs用vis可能会劣势路抢占优势路
char mp[120][120];
int dis[120][120][4];
int mv[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

struct ty{
    int x, y, dir, dis;
    bool operator < (const ty &a) const {
        return dis > a.dis;
    }
};

int main(){
    int n, sx, sy, ex, ey;
    cin >> n;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cin >> mp[i][j];
            if(mp[i][j] == 'A') sx = i, sy = j;
            if(mp[i][j] == 'B') ex = i, ey = j;
        }
    }
    memset(dis, 0x3f, sizeof(dis));
    priority_queue<ty> q;

    for(int i = 0; i < 4; i++){
        dis[sx][sy][i] = 0;
        q.push({sx, sy, i, 0});
    }

    while(!q.empty()){
        ty tmp = q.top(); q.pop();
        if(tmp.dis > dis[tmp.x][tmp.y][tmp.dir]) continue;

        for(int i = 0; i < 4; i++){
            int tx = tmp.x + mv[i][0];
            int ty = tmp.y + mv[i][1];
            if(tx<1||tx>n||ty<1||ty>n||mp[tx][ty]=='x') continue;
            int nd = tmp.dis + (i != tmp.dir);
            if(dis[tx][ty][i] > nd){
                dis[tx][ty][i] = nd;
                q.push({tx, ty, i, nd});
            }
        }
    }
    int ans = INT_MAX;
    for(int i = 0; i < 4; i++) ans = min(ans, dis[ex][ey][i]);
    cout << (ans == 0x3f3f3f3f ? -1 : ans) << endl;
    return 0;
}

别的佬的,bfs思路更清晰

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