Description
现在Yaoge在梦境中,他变成了一个小精灵,被困在一个N*M大小的迷宫中。
在这个迷宫中,有些方格中是水池,有些方格中则充满了岩浆。
如果Yaoge需要通过水池的格子,则需要处于水元素的状态;同样,如果他想要通过岩浆的格子,则需要处于火元素的状态。
除此之外,还有一些格子是墙壁,无法通过;另一些格子是空地(包括起点和终点),可以自由通过。
迷宫中有些空地上还放置有属性转化器,可以让Yaoge转化元素状态。
在这个迷宫中,Yaoge每个单位时间只能进行下面的操作之一:
1、如果可行的话,往上下左右四格中的一格走一步(不能走出N*M的方格)
2、如果处在元素转换器上,则可以转变元素状态(水->火 or 火->水)
Yaoge一开始在迷宫的起点,处于水元素的状态,求他至少要花多少时间才能走到迷宫的出口。
Input
第一行有一个整数T,表示数据组数。(T<=20)
接下来有T组数据,每组数据第一行有两个整数N, M。(1 <= N, M <= 100)
之后的 N 行字符串描述了N * M 的迷宫。
其中'S'表示起点,'T'表示终点,'.'表示空地, '#'表示墙壁,'w'表示岩浆,'~'表示水池, '@'表示空地上的属性转化器。
保证每组数据有且仅有一个'S'和一个'T'。
Output
对于每组数据,如果Yaoge能到达终点,则输出一个整数,表示最少需要的时间,否则输出"Sad Yaoge!",并换行。
Sample Input
5 5
.w@..
.S#..
~w#..
.w..~
@w.~T
3 3
@w.
S#~
.#T
Sample Output
Sad Yaoge!
HINT
样例1的走法是:
左下下下【转换】右上上上上右【转换】右右下下下下
Source
思路:一开始bfs但没想出如何表示属性状态(水,火),题解点醒可以用三维来表示当前状态。
用dis[x][y][nature]来表示在点(x,y)以nature状态经过时目前走过的步数,用dp的思想来进行步数的传递。
开始一直RE....结果经高神指出是bfs最后的返回值没有改成-1.....
#include <iostream>
#include <sstream>
#include <ios>
#include <iomanip>
#include <functional>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <climits>
#include <cctype>
using namespace std;
#define XINF INT_MAX
#define INF 0x3FFFFFFF
#define EPS 1e-8
#define MP(X,Y) make_pair(X,Y)
#define PB(X) push_back(X)
#define REP2(X,L,R) for(int X=L;X<=R;X++)
#define DEP(X,R,L) for(int X=R;X>=L;X--)
#define CLR(A,X) memset(A,X,sizeof(A))
#define lowbit(i) (i&(-i))
#define IT iterator
#define max(a,b) (a>b)?a:b
#define min(a,b) (a<b)?a:b
#define pi 3.1415927
#define X first
#define Y second
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<PII> VII;
typedef vector<int> VI;
const int maxn=1e5+5;
const int mod=1e9+7;
const int B=1031;
const int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int dis[120][120][2]; //存储点(x,y),nature为状态的步数
char a[120][120]; //存图
bool vis[100][100];
int sx,sy,tx,ty,xx,yy,m,n; //起点(sx,sy) 终点(tx ty) 临时点(xx,yy)
//状态表示为 水:1 火:0
bool status(int nature){ //判断下一个点是否可以走
if(xx<0 || xx>=n || yy<0 || yy>=m)
return 0;
if(nature==0 && a[xx][yy]=='~')
return 0;
if(nature==1 && a[xx][yy]=='w')
return 0;
if(a[xx][yy]=='#')
return 0;
return 1;
}
int bfs(){ //bfs最短路步数
int x,y,nature;
queue<pair<PII,int> >q;
q.push(MP(MP(sx,sy),1)); //将3个信息make_pair两次入列,初态为水
while(!q.empty()){
x=q.front().X.X;
y=q.front().X.Y;
int nature=q.front().Y;
q.pop();
if(x==tx && y==ty) //走到终点即返回当前步数
return dis[x][y][nature];
for(int i=0;i<4;i++){ //遍历周围四个点
xx=x+dir[i][0];
yy=y+dir[i][1];
if(!status(nature)) continue; //需提前判断,否则dis[xx][yy][nature]下标易越界
if(dis[xx][yy][nature]== -1){
// cout<<xx<<' '<<yy<<' '<<endl;
dis[xx][yy][nature]=dis[x][y][nature]+1; //若是当前状态没走过且可以走即步数转移
q.push(MP(MP(xx,yy),nature)); //新符合条件的点入列
// cout<<dis[xx][yy][nature]<<endl;
}
}
if(a[x][y]=='@'){
if(dis[x][y][!nature]== -1){
dis[x][y][!nature]=dis[x][y][nature]+1; //遇到转换器(并且以另一种状态没有经过过此处时才有意义),状态转换,步数转移。
q.push(MP(MP(x,y),!nature));
}
}
}
if(x!=tx || y!=ty) //无法走到终点,返回-1
return -1;
}
int main(int argc, char** argv) {
int t;
cin>>t;
while(t--){
cin>>n>>m;
getchar();
for(int i=0;i<n;i++)
{
cin>>a[i];
for(int j=0;j<m;j++){
if(a[i][j]=='S'){
sx=i;sy=j;
}
if(a[i][j]=='T'){
tx=i;ty=j;
}
}
}
// cout<<sx<<' '<<sy<<endl;
memset(dis,-1,sizeof(dis)); //步数清空为-1
dis[sx][sy][1]=0; //起点步数为0
int ans=bfs();
// cout<<ans<<endl;
if(ans==-1)
cout<<"Sad Yaoge!"<<endl;
else
cout<<ans<<endl;
}
return 0;
}