链接:登录—专业IT笔试面试备考平台_牛客网
题目描述:
输入:
5 5 1
..S..
.....
.###.
.....
..T..
1 2 3 3
5 5 1
..S..
.....
.###.
.....
..T..
3 3 1 2
5 5 1
S.#..
..#..
###..
.....
....T
0 1 0 2
4 4 2
S#.T
.#.#
.#.#
.#.#
0 0 0 3
2 0 2 2
输出:
6 8 -1 3
这道题跟普通dfs的区别就在于,它是有一个传送门的,那么当然不能像普通dfs一样建立一个队列,然后无脑塞进去再拿出来,因为我们塞进去的可能是通过传送门到达的地方,而dfs建队列的原则是先进入队列的一定是离起点最近的,那么传送门所带来的距离的不确定性就让我们无法正常使用queue。
但是再一想,我们关心的其实不是进入队列的顺序,因为它最终要影响的其实是出队的顺序,而出队的顺序,由该点距离起点的距离决定,既然如此,就可以建一个优先队列来存储,我们依然可以无脑塞进去,因为优先队列可以保证我们的距离始终有序。
另一个问题是如何存储传送门的起点和终点。显然,用一个vector建立邻接表就可以了。
关于优先队列的排序,我们要以到起点的距离为标准,所以可以建一个结构体,存放步数,步数就是排序的标准。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,q;
struct ty{//建立结构体
int x,y,step;
bool operator<(const ty& s)const{
return step>s.step;//重载<符号
}
};
bool vis[310][310];//标记是否走过
ty star,ed;//起终点
int dir[][4]={{1,0},{-1,0},{0,1},{0,-1}};
char mas[310][310];
vector<int> v[90010];//用一个数来存二维信息,故开一个int就可以了
bool inmap(int x,int y){
return x>=0&&y>=0&&x<n&&y<m;
}
void bfs(){
memset(vis,0,sizeof(vis));
priority_queue<ty> q;
q.push(star);
vis[star.x][star.y]=1;
while(!q.empty()){
ty t=q.top();
q.pop();
int x=t.x,y=t.y;
if(mas[x][y]=='T') {cout<<t.step<<endl;return;}
for(int i=0;i<4;++i){
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(inmap(xx,yy)&&!vis[xx][yy]&&mas[xx][yy]!='#'){
vis[xx][yy]=1;
q.push({xx,yy,t.step+1});
}
}
for(int i:v[x*n+y]){
int a=i/n;
int b=i%n;
if(inmap(a,b)&&mas[a][b]!='#'&&!vis[a][b]){
vis[a][b]=1;
q.push({a,b,t.step+3});
}
}
}
cout<<-1<<endl;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while(cin>>n>>m>>q){
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
cin>>mas[i][j];
v[i*n+j].clear();//清空vector,因为有多组样例!
if(mas[i][j]=='S') star={i,j};
if(mas[i][j]=='T') ed={i,j};
}
}
for(int i=1;i<=q;++i){
ty s1,s2;
cin>>s1.x>>s1.y>>s2.x>>s2.y;
v[(s1.x)*n+s1.y].push_back((s2.x)*n+s2.y);
}
bfs();
}
return 0;
}
因为是多组样例,要特别注意相关定义的清空包括vector、priority_queue、vis等。细节没有太多,跟普通dfs相比只是改了一个优先队列而已。
一道相关的题(状态更加复杂一些,要对vis进行变化)