视频题解戳我
题目描述
精通程序设计的 Applese 双写了一个游戏。在这个游戏中,它被困在了一个 n×mn×m 的迷宫中,它想要逃出这个迷宫。
在迷宫中,有一些方格是水池,只有当 Applese 处于水属性的时候才可以通过;有一些方格是岩浆,只有当 Applese 是火属性的时候可以通过;有一些方格是墙壁,无论如何都无法通过;另一些格子是空地(包括起点和终点),可以自由通过。在一些空地上有神秘道具可以让 Applese 转换自己的属性(从水属性变为火属性或从火属性变为水属性,需要一个单位的时间)。已知 Applese 在一个单位的时间内可以朝四个方向行走一格,且开始处于水属性,位于空地的道具拾取后只能在该处立即使用(或者不使用),且可以多次使用。求它走出迷宫需要的最少时间。
输入描述:
第一行两个正整数 n, m 表示迷宫的大小。
接下来 n 行,每行长度为 m 的字符串。描述地图。
其中 'S' 表示起点,'T' 表示终点,'.' 表示空地,'w'表示岩浆,'~'表示水池,'@' 表示道具,'#'表示障碍。
保证地图中的起点和终点只有一个,道具都位于空地。
输出描述:
输出一个整数,表示 Applese 走出迷宫的最短时间。特别地,如果 Applese 走不出迷宫,输出 "-1"。
示例1
输入
5 5
.w@..
.S#..
~w#..
.w..~
@w.~T
输出
18
备注:
1≤n,m≤100
解题思路:这是一道稍复杂的搜索题,复杂之处就是他可以改变状态,水属性和火属性,所以我们开vis数组时需要多开一维,bool vis[maxn][maxn][3]; 1为水属性,0为火属性 ,因为他这里变换状态需要一秒,所以我们不能用普通的队列了,而是优先队列,严格将时间少的放前面,(因为变换状态需要时间,所以可能会把时间多的放到队列前面),下面直接看代码吧:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=105;
int mp[maxn][maxn],n,m,sx,sy,ex,ey;
bool vis[maxn][maxn][3]; //1为水属性,0为火属性
int ans=inf;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
struct node{
int x;
int y;
int step;
int state;
bool operator < (const node &x) const{
return step > x.step;
}
};
bool pd(int nx,int ny,int nsta){ //第一步判断是否可走
if(!vis[nx][ny][nsta] && mp[nx][ny]!=-1 && nx>=1 && nx<=n
&& ny>=1 && ny<=m) return true;
else return false;
}
bool solve(int sx,int sy){
priority_queue<node> q;
q.push(node{sx,sy,0,1}); //初始为水属性
while(!q.empty()){
node np=q.top();
q.pop();
int x=np.x,y=np.y,nstep=np.step,nsta=np.state;
if(x==ex && y==ey){
ans=nstep;
return true;
}
for(int i=0;i<4;++i){
int nx=x+dx[i],ny=y+dy[i];
if(pd(nx,ny,nsta)){
if(mp[nx][ny]==0) q.push(node{nx,ny,nstep+1,nsta}),vis[nx][ny][nsta]=1;
else if(mp[nx][ny]==nsta+1) q.push(node{nx,ny,nstep+1,nsta}),vis[nx][ny][nsta]=1;
//属性相符可走,属性和标记刚好差1
else if(mp[nx][ny]==3){ //变换属性,变或者不变
q.push(node{nx,ny,nstep+1,nsta}),vis[nx][ny][nsta]=1;
q.push(node{nx,ny,nstep+2,1-nsta}),vis[nx][ny][1-nsta]=1;
}
}
}
}
return false;
}
int main(){
std::ios::sync_with_stdio(0);
cin>>n>>m;
char tp;
for(int i=1;i<=n;++i){ //将对应的字符变成对应数字
for(int j=1;j<=m;++j){
cin>>tp;
if(tp=='S') sx=i,sy=j,mp[i][j]=0;
else if(tp=='T') ex=i,ey=j,mp[i][j]=0;
else if(tp=='.') mp[i][j]=0;
else if(tp=='w') mp[i][j]=1;
else if(tp=='~') mp[i][j]=2;
else if(tp=='@') mp[i][j]=3;
else if(tp=='#') mp[i][j]=-1;
}
}
if(solve(sx,sy)) cout<<ans<<endl;
else cout<<-1<<endl;
return 0;
}