题意
- 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;
}