思路是把迷宫转换成图,相邻格之间建权为1的边,传送点之间建权为0的边,然后跑一遍Dijkstra;考虑到会有直接走过传送点的情况,最后循着路线碰到这样的情况就把答案+2(先出传送点,再回来)。 但是为什么就WA了一堆呢……
#include <bits/stdc++.h>
using namespace std;
int n,m;//高,宽
int G[310][310];//原始图(迷宫)
int num;//新图节点的数量
int head[90010],nxt[400010],To[400010],w[400010],tot;//前向星存图
int tp[30];//传送点
int st,ed;//起止点
int d[90010];//dijkstra距离
int vis[90010];//dijkstra是否被访问过
int pre[90010];
int isTp[90010];
int nTp[30];
map<pair<int, int> ,int>id;//迷宫中(i,j)对应新图的节点编号,id[make_pair(i,j)]
void AddEdge(int fr,int to,int v){//前向星存图(从fr到to建一条长度为v的边)
nxt[++tot]=head[fr];
head[fr]=tot;
To[tot]=to;
w[tot]=v;
}
int HadId(int i,int j){//是否已经分配了Id
return id.count(make_pair(i,j));
}
int Id(int i,int j){//(i,j)的编号
return id[make_pair(i,j)];
}
void SetId(int i,int j){//分配id给(i,j)
id[make_pair(i,j)]=++num;
// cout<<"^%%";
}
void Build(int fi,int fj,int ti,int tj){//从(fi,fj)到(ti,tj)建边
if(ti<=0 || ti>n || tj<=0 ||tj>m)return;//(ti,tj)是否越界
if(G[ti][tj]==-1)return;//(ti,tj)是否为墙
if(!HadId(ti,tj))SetId(ti,tj);//(ti,tj)是否已有编号
AddEdge(Id(fi,fj),Id(ti,tj),1);//从(fi,fj)到(ti,tj)建边
}
void BDnormal(int i,int j){//向四个方向尝试建边
Build(i,j,i+1,j);
Build(i,j,i-1,j);
Build(i,j,i,j+1);
Build(i,j,i,j-1);
}
int main(){
// freopen("4.txt","w",stdout);
scanf("%d%d",&n,&m);//输入宽、高
for(int i=1;i<=n;i++){
string temp;//读入每一行
cin>>temp;
temp=" "+temp;//便于读取,在字符串前加一个空格以将每一行开头的下标置为1
for(int j=1;j<=m;j++){
if(temp[j]=='#')G[i][j]=-1;//-1表示墙
else if(temp[j]=='=')G[i][j]=-2;//-2表示出口ed
else if(temp[j]=='@')G[i][j]=-3;//-3表示开头st
else if(temp[j]=='.')G[i][j]=-4;//-4表示空
else G[i][j]=temp[j]-'A';//>=0表示传送机
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(G[i][j]==-1)continue;
if(!HadId(i,j))SetId(i,j);//如果(i,j)没有编号,分配给它
if(G[i][j]==-2)
ed=Id(i,j);//如果为出口,设置ed为其编号
else if(G[i][j]==-3)
st=Id(i,j);//如果为出发点,设置st为其编号
else if(G[i][j]>=0){//如果为传送机
isTp[Id(i,j)]=G[i][j];
nTp[G[i][j]]++;
if(tp[G[i][j]]){//如果已经记录过同类型传送机
AddEdge(Id(i,j),tp[G[i][j]],0);//建双向边
AddEdge(tp[G[i][j]],Id(i,j),0);
}
else tp[G[i][j]]=Id(i,j);//如果没有记录过该类传送机,记录之
}
BDnormal(i,j);//尝试向四周建边
}
priority_queue<pair<int,int> >q;//d,id
for(int i=1;i<=num;i++)d[i]=0x7fffffff/2;//初始化
d[st]=0;
q.push(make_pair(0,st));//将起始点入堆
while(!q.empty()){//堆优化的dijkstra
int now=q.top().second;
q.pop();
if(vis[now])continue;
vis[now]=1;
for(int i=head[now];i;i=nxt[i]){
int v=To[i];
if(d[now]+w[i]<d[v]){
d[v]=d[now]+w[i];
q.push(make_pair(-d[v],v));
pre[v]=now;
}
}
}
int n1,n2,n3;
for(int i=ed;pre[pre[i]];i=pre[i]){
n1=i;n2=pre[i];n3=pre[pre[i]];
if(isTp[n2]&& isTp[n1]!=isTp[n2] && isTp[n2]!=isTp[n3])
if(nTp[isTp[n2]]){d[ed]+=2;}
}
printf("%d\n",d[ed]);
return 0;
}