题意

  • 走迷宫,迷宫中有传送门,使用传送门需要花费三秒,求解从起点到终点的最短时间

思路

  • 相较于传统搜索,出现的问题是对于一个点可能有多个到达时间,我们希望记录这多个时间中最短的时间
  • 对于传送门,由于同一个点可能有多个传送门,所以不能使用点对点的映射,使用点对数组的映射,map<int,vector>
  • 换言之,对于一个点的多个时间,我们处理完最短的就可以了,同时对于所有路径,我们总希望先处理当前时间最短的时间,故从维护队列变为维护优先队列,维护一个大顶堆,存储坐标和时间的pair
  • 同时对于传统的vis数组,不再是只要走到就更新,而是时间最早的被处理后,更新vis
  • 由于上一条,所以判断达到终点的最短时间也应当在终点第一次位于堆顶后,再进行输出
  • 由于传送门可能位于起点,所以bfs的初始化除了将自己入队,还要将起点的传送终点也入队
  • 由于传送的终点可能位于陷阱之中或是已经走过的地方,所以,每次在将传送终点入队前,需要先判断是否合法

注意

  • 行列别读反
  • 由于多组数据,vis,传送门,地图每次都需要初始化
  • 对于将坐标转换为一个数这件事,0开始:n行m列的(x,y)=>xm+y,1开始:n行m列的(x,y)=>x(m+1)+y

AC代码

#include<bits/stdc++.h>
using namespace std;
char a[320][320];
int vis[320][320];
int n,m,q;
int d[4][2]={0,1,0,-1,1,0,-1,0};
map<int,vector<int>>dr;
struct cmp{
  bool operator()(pair<int,int> &a,pair<int,int> &b){
  	return a.second>b.second;
  }
};

int bfs(int s,int e){
  priority_queue<pair<int,int>,vector<pair<int,int>>,cmp>q;
  q.push({s,0});
//	vis[s/m][s%m]=1;
  if(dr.find(s)!=dr.end()){
  	for(auto &j:dr[s]){
  		if(a[j/m][j%m]=='#'||vis[j/m][j%m]==1)continue;
  		q.push({j,3});
  	}
  }
  while(q.size()){
  	int x=q.top().first/m;
  	int y=q.top().first%m;
  	int step=q.top().second;
  	q.pop();
  	if(vis[x][y])continue;		
  	vis[x][y]=1;
  	if(x==e/m&&y==e%m) return step;

  	for(int i=0;i<4;i++){
  		int tx=x+d[i][0];
  		int ty=y+d[i][1];
  		if(tx<0||tx>=n||ty<0||ty>=m||a[tx][ty]=='#'||vis[tx][ty]==1)continue;
  		q.push({tx*m+ty,step+1});
  		if(dr.find(tx*m+ty)!=dr.end()){
  			for(auto &j:dr[tx*m+ty]){
  				if(a[j/m][j%m]=='#'||vis[j/m][j%m]==1)continue;
  				q.push({j,step+4});
  			}
  		}
  	}
  }
  return -1;
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);cout.tie(0);
  while(cin>>n>>m>>q){
  	int start,en;
  	memset(a,'\0',sizeof(a));
  	memset(vis,0,sizeof(vis));
  	dr.clear();
  	for(int i=0;i<n;i++){
  		for(int j=0;j<m;j++){
  			cin>>a[i][j];
  			if(a[i][j]=='S') start=m*i+j;
  			if(a[i][j]=='T') en=m*i+j;
  		}
  	}
  	for(int i=0;i<q;i++){
  		int x1,y1,x2,y2;
  		cin>>x1>>y1>>x2>>y2;
  		dr[x1*m+y1].push_back(x2*m+y2);
  	}
  	cout<<bfs(start,en)<<'\n';
  }


  return 0;
}