E-魔法之森的蘑菇_牛客周赛 Round 37 (nowcoder.com)
问题描述:经典bfs(有障碍物的权值相同最短路)改,额外加了一个条件,遇到.
不能转向,只能向同一方向直走,遇到*
可以转向,但是不能调头(往回走)。
我刚开始做的时候,直接设置二维数组表示 ( x , y ) (x, y) (x,y),加上限制条件走bfs。对了百分之二三十,以为bfs写错了,一直调也没有发现错误。无奈看题解。
看了题解才发现我太惯性思维了,点 ( x , y ) (x, y) (x,y)上不止一种状态。点 ( x , y ) (x, y) (x,y)上会有 ( x , y , l e f t ) (x, y, left) (x,y,left), ( x , y , r i g h t ) (x, y, right) (x,y,right), ( x , y , u p ) (x, y, up) (x,y,up), ( x , y , d o w n ) (x, y, down) (x,y,down),即由 ( x i , y i , N U L L ) (x_i, y_i, NULL) (xi,yi,NULL)到 ( x , y ) (x, y) (x,y)的方向是不一样的,根据限制条件, ( x , y ) (x, y) (x,y)的行动也是不一样的。
因此在前置基础上加上方向,设为三维数组进行bfs即可。
代码如下:(指向的处理大部分是原来二维时写的,可以用dir
找前驱到该点的编号进行优化以此简化代码)
#include <bits/stdc++.h>
using namespace std;
int fx[] = {0, 0, 1, -1};
int fy[] = {1, -1, 0, 0};
struct no {
int x,y,ox,oy,cnt;
};
void solve() {
int n,m; cin>>n>>m;
vector<string> ph(n);
for(auto &t: ph) cin>>t;
// 三维数组
vector<vector<vector<int>>> vis(n, vector<vector<int>>(m, vector<int>(5,0)));
queue<no> q;
int stx, sty;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(ph[i][j] == 'S') {
stx = i, sty = j;
break;
}
}
}
// 计算 (nowx, nowy) <--> (ox, oy)
// 指向无所谓,只要指向都用一种都可以(严格上用 (ox, oy) --> (nowx, nowy) ,因为有具体的含义
auto dir = [&](int nowx, int nowy, int ox, int oy) ->int {
for(int i = 0; i < 4; ++i) {
if(nowx + fx[i] == ox && nowy + fy[i] == oy) return i;
}
// 无效的返回值 (牛客编辑器会提醒,太良心了
return -1;
};
// 先搜起点,起点特殊,没有前驱
for(int i = 0; i < 4; ++i) {
int xx = stx + fx[i], yy = sty + fy[i];
if(xx < 0 || xx >= n || yy < 0 || yy >= m) continue;
if(ph[xx][yy] == '#') continue;
if(ph[xx][yy] == 'T') {
cout<<1<<'\n';
return ;
}
q.push({xx, yy, stx, sty, 1});
vis[xx][yy][dir(xx,yy,stx,sty)] = true;
}
// 开始bfs
while(q.size()) {
auto tmp = q.front(); q.pop();
int x = tmp.x, y = tmp.y, ox = tmp.ox, oy = tmp.oy, lastcnt = tmp.cnt;
for(int i = 0; i < 4; ++i) {
int xx = x + fx[i], yy = y + fy[i];
if(xx < 0 || xx >= n || yy < 0 || yy >= m) continue;
if(ph[xx][yy] == '#') continue;
// "." 和 "*" 分开处理
if(ph[x][y] == '.') {
if(xx - x == x - ox && yy - y == y - oy) {
// 如果是终点,直接输出
if(ph[xx][yy] == 'T') {
cout<<lastcnt + 1<<'\n';
return ;
} else {
if(vis[xx][yy][dir(xx, yy, x, y)]) continue;
q.push({xx, yy, x, y, lastcnt + 1});
// 如果满足 "."的限制条件可以走(xx, yy) 才可以设置为true
vis[xx][yy][dir(xx, yy, x, y)] = true;
}
}
// 同 "."的处理思路
} else if(ph[x][y] == '*') {
if(xx != ox || yy != oy) {
if(ph[xx][yy] == 'T') {
cout<<lastcnt + 1<<'\n';
return ;
} else {
if(vis[xx][yy][dir(xx, yy, x, y)]) continue;
q.push({xx, yy, x, y, lastcnt + 1});
vis[xx][yy][dir(xx, yy, x, y)] = 1;
}
}
}
}
}
cout<<-1<<'\n';
}
int main()
{
int t; cin>>t;
while(t--) solve();
}