P1825
#include<bits/stdc++.h>
using namespace std;
char mp[301][301];
int mmp[301][301];//图 值图
int d[90005][2];//手写队
int cs[26][2][3],/*传送门出口——传送门必须穿两次才不会漏;*/
dx[4]={1,-1,0,0},
dy[4]={0,0,1,-1}; //移动
int n,m;
int in(int x,int y){
return x>=0&&x<n&&y>=0&&y<m&&mp[x][y]!='#';
}
int check(int c,int x,int y){
if(cs[c][0][0]==x&&cs[c][0][1]==y){ //A点
if(cs[c][1][2]){
return 1;//可走 (是对点的出口且本点出口未使用)
}
else return false;//不可
}
else{//B点
if(cs[c][0][2]){
return 2;//可走 (是对点的出口且本点出口未使用)
}
else return false;//不可
}
}
void bfs(int x,int y){
int head=0,tail=1;
d[tail][0]=x,d[tail][1]=y;
mmp[x][y]=0;
do{
head++;
int xn=d[head][0],yn=d[head][1];
for(int i=0;i<4;i++){
int nx=xn+dx[i],ny=yn+dy[i];
if(mp[nx][ny]=='='){//终点
cout << mmp[xn][yn]+1;
return ;
}
if(in(nx,ny)){//非墙
if(mp[nx][ny]=='.'){ //简单通过
tail++;
if(d[tail][0]&&d[tail][1]) tail++;
d[tail][0]=nx,d[tail][1]=ny;mmp[nx][ny]=mmp[xn][yn]+1;
}
else if(mp[nx][ny]>='A'&&mp[nx][ny]<='Z'){
int c=mp[nx][ny]-'A';
int ack; int key=check(c,nx,ny);
if(key){ //1为1点入队,2为0点入队并标记不可用 把起始点提前 两 步入队
ack=(key==1?1:0);
tail++;
int s1=cs[c][ack][0],s2=cs[c][ack][1];
d[tail][0]=s1;
d[tail][1]=s2;
mmp[s1][s2]=mmp[xn][yn]+1;
cs[c][ack][2]=false;
tail+=2;
d[tail][0]=cs[c][!ack][0];
d[tail][1]=cs[c][!ack][1];
tail-=2;
}
}
}
}
}while(head<tail);
}
int main(){
cin >> n >> m;
int x,y;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;cin >> c;
if(c=='@') x=i,y=j,mp[x][y]='#';
else if(c>='A'&&c<='Z'){//存出口坐标
if(cs[c-'A'][0][2]==false){
cs[c-'A'][0][0]=i,cs[c-'A'][0][1]=j;
cs[c-'A'][0][2]=true;
}
else{
cs[c-'A'][1][0]=i,cs[c-'A'][1][1]=j;
cs[c-'A'][1][2]=true;
}
}
mp[i][j]=c;
}
}
bfs(x,y);
return 0;
}
搜索初学 只会用手打队列 错误点全部是RE QAQ