这题关键是如何处理进传送门时间+3这个条件,因为传送后走的路线会对平常走的路线(用传统vis数组判断是否走过)造成影响,而且传送后有可能比不传送时间要短。因此思路是尽可能单独处理传送门的情况,或者将传送门的情况放在比较后的位置考虑,基于第二种思路,我是用了优先队列。
AC代码如下:
#include<bits/stdc++.h>
#include<stdio.h>
using namespace std;
int n,m;
char a[304][304];
int vis[304][304];//访问过.和#
int vis2[304][304];//访问过传送门
int move1[4][2]={0,1,0,-1,1,0,-1,0};//move有些编译器会报错
int min1;
struct point
{
int x;
int y;
int step;
bool operator<(const point a) const //优先队列默认是最大在上面,现在我们要每次把step最小放上面
{
return a.step<step;
}
};
point cs[304][304];//传送门
int bfs(point begin,point end)
{
priority_queue<point>que;
que.push(begin);
point cur;//当前层节点
while(!que.empty())//宽搜模板
{
cur=que.top();
que.pop();
point temp;
//if(a[cur.x][cur.y]=='#')return -1;//一开始以为起点和终点可能有陷阱,实际上不可能
if(cur.x==end.x&&cur.y==end.y)
{
min1=min(min1,cur.step);//取最小值,也可直接return cur.step
}
temp.x=cs[cur.x][cur.y].x;
temp.y=cs[cur.x][cur.y].y;
if(vis[temp.x][temp.y]==0&&vis2[cur.x][cur.y]==2&&a[cur.x][cur.y]!='#'&&a[temp.x][temp.y]!='#')
{
temp.step=cur.step+3;
que.push(temp);
vis2[cur.x][cur.y]=1;
//vis[temp.x][temp.y]=1;//
}
for(int i=0;i<4;i++)
{
temp.x=cur.x+move1[i][0];
temp.y=cur.y+move1[i][1];
//cout<<temp.x<<" "<<temp.y<<" "<<temp.step<<endl;
if(temp.x>=0&&temp.x<n&&temp.y>=0&&temp.y<m&&vis[temp.x][temp.y]==0&&a[temp.x][temp.y]!='#')
{
temp.step=cur.step+1;
vis[temp.x][temp.y]=1;
que.push(temp);
}
}
}
if(min1!=1e9)
return min1;
else
return -1;//查询完毕,队列为空,返回-1
}
int main()
{
int q;
while(cin>>n>>m>>q)
{
memset(vis,0,sizeof(vis));
memset(cs,0,sizeof(cs));
memset(vis2,0,sizeof(vis2));
min1=1e9;
point begin,end;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>a[i][j];
if(a[i][j]=='S')
{
begin.x=i;
begin.y=j;
begin.step=0;
vis[begin.x][begin.y]=1;
}
if(a[i][j]=='T')
{
end.x=i;
end.y=j;
}
}
}
for(int j=0;j<q;j++)
{
int a,b,c,d;
cin>>a>>b;
cin>>cs[a][b].x>>cs[a][b].y;
vis2[a][b]=2;
}
cout<<bfs(begin,end)<<endl;
}
}
#include<bits/stdc++.h>
#include<stdio.h>
using namespace std;
int n,m;
char a[304][304];
int vis[304][304];//访问过.和#
int vis2[304][304];//访问过传送门
int move1[4][2]={0,1,0,-1,1,0,-1,0};//move有些编译器会报错
int min1;
struct point
{
int x;
int y;
int step;
bool operator<(const point a) const //优先队列默认是最大在上面,现在我们要每次把step最小放上面
{
return a.step<step;
}
};
point cs[304][304];//传送门
int bfs(point begin,point end)
{
priority_queue<point>que;
que.push(begin);
point cur;//当前层节点
while(!que.empty())//宽搜模板
{
cur=que.top();
que.pop();
point temp;
//if(a[cur.x][cur.y]=='#')return -1;//一开始以为起点和终点可能有陷阱,实际上不可能
if(cur.x==end.x&&cur.y==end.y)
{
min1=min(min1,cur.step);//取最小值,也可直接return cur.step
}
temp.x=cs[cur.x][cur.y].x;
temp.y=cs[cur.x][cur.y].y;
if(vis[temp.x][temp.y]==0&&vis2[cur.x][cur.y]==2&&a[cur.x][cur.y]!='#'&&a[temp.x][temp.y]!='#')
{
temp.step=cur.step+3;
que.push(temp);
vis2[cur.x][cur.y]=1;
//vis[temp.x][temp.y]=1;//
}
for(int i=0;i<4;i++)
{
temp.x=cur.x+move1[i][0];
temp.y=cur.y+move1[i][1];
//cout<<temp.x<<" "<<temp.y<<" "<<temp.step<<endl;
if(temp.x>=0&&temp.x<n&&temp.y>=0&&temp.y<m&&vis[temp.x][temp.y]==0&&a[temp.x][temp.y]!='#')
{
temp.step=cur.step+1;
vis[temp.x][temp.y]=1;
que.push(temp);
}
}
}
if(min1!=1e9)
return min1;
else
return -1;//查询完毕,队列为空,返回-1
}
int main()
{
int q;
while(cin>>n>>m>>q)
{
memset(vis,0,sizeof(vis));
memset(cs,0,sizeof(cs));
memset(vis2,0,sizeof(vis2));
min1=1e9;
point begin,end;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>a[i][j];
if(a[i][j]=='S')
{
begin.x=i;
begin.y=j;
begin.step=0;
vis[begin.x][begin.y]=1;
}
if(a[i][j]=='T')
{
end.x=i;
end.y=j;
}
}
}
for(int j=0;j<q;j++)
{
int a,b,c,d;
cin>>a>>b;
cin>>cs[a][b].x>>cs[a][b].y;
vis2[a][b]=2;
}
cout<<bfs(begin,end)<<endl;
}
}