题目简述:在n*m的方格中,要求从左上角的方格移动到右下角的方格,且满足以下规则:
1.障碍物不能进入
2.仅能往上下左右四方向移动
3.走入一个传送门后,立即移动到唯一对应的另一个传送门
这道题和一般的bfs求解迷宫略有区别。
Q1:如何记录传送门位置?
A:如果我们找到一个传送门的位置,可以考虑记录在哈希表里而不是用O(n^4)的暴力去寻找另外一个传送门的坐标。一个传送门名称(A-Z)记录了四个数字,两个表示横坐标,两个表示纵坐标。
tips:传送门有多个
Q2:为什么我应该使用bfs,而不是dfs?
A:因为本题使用求解的是最短时间!如果使用dfs,需要把所有路径遍历一遍取最小值,时间不合法。使用bfs可以通过打上vis数组的标记来防止重复走入同一格中。显然,后走入一格是要比先走入同一格的答案要劣的
Q3:你说的“略有区别”区别在哪?
A:一般的迷宫问题需要在将一个坐标信息入队前就标记vis。但是对于传送门来说,这是不合适的:
例如以下数据:
6 7
01A1000
0101010
0101010
0100010
0111110
00000A0
如果我们选择在踏入右下角的传送门时标记两个传送门,显然是不合适的:因为标记以后无法再次进入传送门而需要走一条远路。
如果我们走入传送门后,选择往下走一步,再次进入传送门,可以发现传送回来后可以直接到达终点。
可以这样理解:两个传送门并不是同一个格子。传送门的作用相当于把两个格子的方位互换了一下,而其意义不变。
如果看不懂以上这个抽象的概念,可以如此解释:为防止这种样例,考虑到重复踏入同一位置的同一传送门是无意义的,我们在进入传送门时,只对入传送门进行标记。
搜索代码:
/*
py 代表偏移量
x y 代表当前处理的坐标
nx ny代表走了一步后的坐标
a 存的是地图
b 存的是传送门信息
node 这个类代表当前位置信息,xy是坐标,step是到达这个坐标走的步数
*/
for(int i=0;i<4;i++){
int nx=x+py[i][0];
int ny=y+py[i][1];
if(nx<0 || nx>=n || ny<0 || ny>=m){ //边界判断,重复性判断,障碍判断
continue;
}
if(a[nx][ny]=='1' || vis[nx][ny]==1){
continue;
}else if(a[nx][ny]=='0'){
node L;
L.x=nx;
L.y=ny;
vis[nx][ny]=1;
L.step=st+1;
q.push(L);
}else{
int x1=b[a[nx][ny]-'A'][0],y1=b[a[nx][ny]-'A'][1],x2=b[a[nx][ny]-'A'][2],y2=b[a[nx][ny]-'A'][3];
vis[nx][ny]=1;
if(nx==x1 && ny==y1){
nx=x2;
ny=y2;
}else{
nx=x1;
ny=y1;
}
node L;
L.x=nx;
L.y=ny;
L.step=st+1;
q.push(L);
}
}