题目:P1825
#include<iostream>
#include<queue>
using namespace std;
struct ST{
int x;
int y;
};
queue<ST> q;
const int nx[4]={1,-1,0,0},ny[4]={0,0,1,-1};
int n,m,ans[305][305],ansx,ansy;
char map[305][305];//地图
ST chuan[256];//下标:传送门的编号 内容:传送门的传送位置
int vis[305][305];//记录坐标(i,j)需要走几步
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>map[i][j];
if(map[i][j]=='@'){//如果是起点,将这个坐标插入队列中
q.push({i,j});
}
if(map[i][j]=='='){//如果是终点,记录当前坐标,输出ans【i】【j】即可获得所需步数
ansx=i;
ansy=j;
}
if(map[i][j]>='A'&&map[i][j]<='Z'){//如果他是一个大写字母,则他是传送门
if(chuan[map[i][j]+('a'-'A')].x==0){//如果他的坐标对应的传送门没有标记过,说明他传送时是正向传送
chuan[map[i][j]].x=i;
chuan[map[i][j]].y=j;
map[i][j]+=('a'-'A');//为了双向传送,把第一次出现的位置改成小写字母,此处把从小写字母传送至大写字母称之为正向传送 ; 坐标为小写字母坐标
}
else{//如果不是正向传送,则是逆向传送
chuan[map[i][j]].x=i;
chuan[map[i][j]].y=j; //相反,把大写字母传送至小写字母称之为逆向传送 ; 坐标为大写字母坐标
}
}
}
}
while(!q.empty()){
ST now=q.front();
int nowx=now.x;
int nowy=now.y;
q.pop();//提出现在位置的坐标
if(nowx==ansx&&nowy==ansy){
break;
}
if(vis[nowx][nowy]>2) continue;//如果这个位置走了两遍,则这个位置再次走一定是重复走 ,所以直接continue
vis[nowx][nowy]++; //这个位置走过次数加一
if(map[nowx][nowy]>='A'&&map[nowx][nowy]<='Z'){//如果这是一个大写字母,则需要把他传送至小写字母处
int posx=nowx;
int posy=nowy;
posx=chuan[map[nowx+('a'-'A')][nowy+('a'-'A')]].x;
posy=chuan[map[nowx+('a'-'A')][nowy+('a'-'A')]].y;
nowx=posx;
nowy=posy;
vis[nowx][nowy]++;//把posx与posy对应为传送后的坐标,然后把传送后的位置走的次数加一
}
if(map[nowx][nowy]>='a'&&map[nowx][nowy]<='z'){//如果这是一个大写字母,则需要把他传送至小写字母处
int posx=nowx;
int posy=nowy;
posx=chuan[map[nowx-('a'-'A')][nowy-('a'-'A')]].x;
posy=chuan[map[nowx-('a'-'A')][nowy-('a'-'A')]].y;
nowx=posx;
nowy=posy;
vis[nowx][nowy]++;//把posx与posy对应为传送后的坐标,然后把传送后的位置走的次数加一
}
for(int i=0;i<4;i++){
int dx=nowx+nx[i];
int dy=nowy+ny[i];
if(dx<1||dy<1||dx>n||dy>m){
continue;
}
q.push({dx,dy});
ans[dx][dy]=ans[nowx][nowy]+1;//向四个方向分别延伸, 然后延伸后的坐标所需步数为现在坐标加一 ,如果新坐标出界则continue
}
}
cout<<ans[ansx][ansy];
}