shuoj1962 Water and Fire Maze

2 篇文章 0 订阅

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

2
5 5
.w@..
.S#..
~w#..
.w..~
@w.~T   

3 3
@w.
S#~
.#T

Sample Output

18
Sad Yaoge!

HINT

样例1的走法是:


左下下下【转换】右上上上上右【转换】右右下下下下

Source

Curs0r



思路:一开始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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值