题目考点:bfs or dfs or dijkstra(蒟蒻优先想到bfs,就先粘上bfs吧,日后有时间补上其他的)

题目大意:走迷宫起点到终点至少需要转90度弯共几次

题目分析:优先队列按照转弯次数从小到大,基于贪心思想得到最优解。在bfs版子的基础上,在结点中多加一个该点是从哪个方向走来的即可。 需要注意的是,我们走过的点不能单纯的标记走过后就不能再走,而是说走过该点之后,如果下次走到该点时,需要的转弯次数更少,或者走到该点时方向不同的话,还是要维护进队列的。(如下方样例)

卡bfs模板样例:

4
A . . .
. . . .
x x B .
. . . .
// 该样例从(2,2)或(1,3)都可以到(2,3),但是方向不同,也需要添加到队列   

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;

const int N = 110;
const int INF = 0x3f3f3f3f;
int n, stx, sty, edx, edy;
char mp[N][N];
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int v[N][N];

struct POS{
    int x, y, d, sum;  // x,y是坐标点,d是来的方向,sum是转弯次数
    bool operator > (const POS& A)const{
        return sum > A.sum;
    }
}pos[N*N];

priority_queue<POS, vector<POS>, greater<POS> > r;

int dfs(int x, int y, int dd)
{
    int cnt = INF;
    if(x<1 || x>n || y<1 || y>n || mp[x][y] == 'x')
        return INF;

    v[stx][sty] = v[x][y] = 0;
    r.push({x, y, dd, 0});

    while(r.size())
    {
        auto t = r.top(); r.pop();
        int xx = t.x, yy = t.y;
        int di = t.d, ct = t.sum;

        if(xx == edx && yy == edy)
            cnt = min(cnt, ct);
        //cout << xx << ' ' << yy << ":" ;
        for(int i = 0; i < 4; i++)
        {
            int tx = xx + dir[i][0], ty = yy + dir[i][1];
            if(mp[tx][ty] == 'x') continue;
            if(tx<1 || tx>n || ty<1 || ty>n)
                continue;
          
            int tt = ct;
            if(di != i) tt += 1;  // 方向不同,转弯数+1

            if(tt <= v[tx][ty])
            {
                r.push({tx, ty, i, tt});
                v[tx][ty] = tt;
                //cout << "(" << tx << ',' << ty << ")" << '-' << tt << ' ' ;
            }
        }
        //cout << '\n';
    }
    return cnt;
}

int main()
{
    scanf("%d", &n);

    for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++)
    {
        scanf(" %c", &mp[i][j]);
        if(mp[i][j] == 'A')
            stx = i, sty = j;
        if(mp[i][j] == 'B')
            edx = i, edy = j;
    }

    int ans = INF;
    for(int i = 0; i < 4; i++)  // 由于开始方向未定,因此每个方向走一次
    {
        memset(v, 0x3f, sizeof v);
        while(r.size()) r.pop();
        int x = stx+dir[i][0], y = sty+dir[i][1];
        ans = min(ans, dfs(x, y, i));
    }
    if(ans == INF)
        printf("-1");
    else printf("%d", ans);

    return 0;
}
/*
3
A . .
. . .
x x B
*/