诡异的楼梯
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 19 Accepted Submission(s) : 4
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向.
比如下面的例子里,一开始楼梯在竖直方向,一分钟以后它移动到了水平方向,再过一分钟它又回到了竖直方向.Harry发现对他来说很难找到能使得他最快到达目的地的路线,这时Ron(Harry最好的朋友)告诉Harry正好有一个魔法道具可以帮助他寻找这样的路线,而那个魔法道具上的咒语,正是由你纂写的.
Input
测试数据有多组,每组的表述如下:
第一行有两个数,M和N,接下来是一个M行N列的地图,'*'表示障碍物,'.'表示走廊,'|'或者'-'表示一个楼梯,并且标明了它在一开始时所处的位置:'|'表示的楼梯在最开始是竖直方向,'-'表示的楼梯在一开始是水平方向.地图中还有一个'S'是起点,'T'是目标,0<=M,N<=20,地图中不会出现两个相连的梯子.Harry每秒只能停留在'.'或'S'和'T'所标记的格子内.
Output
只有一行,包含一个数T,表示到达目标的最短时间.
注意:Harry只能每次走到相邻的格子而不能斜走,每移动一次恰好为一分钟,并且Harry登上楼梯并经过楼梯到达对面的整个过程只需要一分钟,Harry从来不在楼梯上停留.并且每次楼梯都恰好在Harry移动完毕以后才改变方向.
Sample Input
5 5
**..T
**.*.
..|..
.*.*.
S....
Sample Output
7
Hint
Hint
地图如下:
Source
Gardon-DYGG Contest 1
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
#define inf 99999999
#define maxn 25
int n,m;
char c;
/*
在迷宫里面加入了变化的楼梯;;
一个小骄傲的地方:
看到好多人判断楼梯的可走性时用了四个if,
我在处理这个问题时先将上左下右按权位排开,
然后分别赋予上下楼梯10,左右楼梯5的数值权重,
在选择方向并扩展时,可以通过与运算判断是否可走,
结合mark(已经步数对二取模)是否为0(0表示远原来状态)
一次判断是否可走。。
关键在于状态的入栈,什么状态该入栈?
如果楼梯可走则走过去时间加一的状态入栈,
如果不可走则原地停留时间加一的状态入栈,
(为什么不是走过去时间加2?
原因在vis数组上的逻辑,走过去时间加二则vis占用的是走过的位置加时间状态,
重点是在原地停留的状态还可以通过其他方式可达(不是必须更长的步数),
这样对于vis数组就有逻辑漏洞了..
如果在原地停留的状态在走完后一直保持可用。。。那么就破坏了bFS本身的最短最优性。。。(名字是自取的)
*/
int sx,sy,ex,ey;
int mp[maxn][maxn];
struct Node
{
int x,y,cnt,step;
Node(int p=0,int q=0,int t=0,int s=0)
{
step=s;
x=p,y=q;
cnt=t;
}
};
int dir1[]={-1,0,1,0};
int dir2[]={0,-1,0,1};//上左下右
bool judge(int x,int y)
{
if(x<0||x>=n) return false;
if(y<0||y>=m) return false;
return true;
}
int vis[maxn][maxn][2];
int BFS()
{
memset(vis,0,sizeof(vis));
int tx,ty;Node tmp;
queue<Node> seq;
seq.push(Node(sx,sy));
vis[sx][sy][0]=1;
while(!seq.empty())
{
Node t=seq.front();
seq.pop();
if(t.x==ex&&t.y==ey) return t.cnt;
int k=8;
for(int i=0;i<4;i++,k/=2)//偶数是上下
{
tx=t.x+dir1[i];
ty=t.y+dir2[i];
int mark= t.cnt%2;
int emark=(mark+1)%2;
if(!judge(tx,ty)) continue;
//if(vis[tx][ty][mark]) continue;
if(mp[tx][ty]>4)
{
if((mp[tx][ty]&k)!=mark)//如果楼梯可以直接走
{
tx+=dir1[i];
ty+=dir2[i];
if(!judge(tx,ty)) continue;
if(vis[tx][ty][emark]) continue;
vis[tx][ty][emark]=1;
seq.push(Node(tx,ty,t.cnt+1));
}
else//停一秒
{
//tx+=dir1[i];
//ty+=dir2[i];
// if(!judge(tx,ty)) continue;
if(vis[t.x][t.y][emark]) continue;
vis[t.x][t.y][emark]=1;
seq.push(Node(t.x,t.y,t.cnt+1));
}
}
else if(mp[tx][ty]==1) continue;
else if(mp[tx][ty]==0)
{
if(vis[tx][ty][emark]) continue;
vis[tx][ty][emark]=1;
seq.push(Node(tx,ty,t.cnt+1));
}
}
}
return -1;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)
{
memset(mp,0,sizeof(mp));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>c;
if(c=='*') mp[i][j]=1;
else if(c=='.') mp[i][j]=0;
else if(c=='S') {sx=i,sy=j;}
else if(c=='T') {ex=i,ey=j;}
else if(c=='|') mp[i][j]=10;
else if(c=='-') mp[i][j]=5;
}
printf("%d\n",BFS());
}
return 0;
}