您的位置:首页 > 其它

hdu 1180:诡异的楼梯(BFS广搜)

2014-01-16 12:20 375 查看

诡异的楼梯

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 7642 Accepted Submission(s): 1830


[align=left]Problem Description[/align]
Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向.
比如下面的例子里,一开始楼梯在竖直方向,一分钟以后它移动到了水平方向,再过一分钟它又回到了竖直方向.Harry发现对他来说很难找到能使得他最快到达目的地的路线,这时Ron(Harry最好的朋友)告诉Harry正好有一个魔法道具可以帮助他寻找这样的路线,而那个魔法道具上的咒语,正是由你纂写的.

[align=left]Input[/align]
测试数据有多组,每组的表述如下:
第一行有两个数,M和N,接下来是一个M行N列的地图,'*'表示障碍物,'.'表示走廊,'|'或者'-'表示一个楼梯,并且标明了它在一开始时所处的位置:'|'表示的楼梯在最开始是竖直方向,'-'表示的楼梯在一开始是水平方向.地图中还有一个'S'是起点,'T'是目标,0<=M,N<=20,地图中不会出现两个相连的梯子.Harry每秒只能停留在'.'或'S'和'T'所标记的格子内.

[align=left]Output[/align]
只有一行,包含一个数T,表示到达目标的最短时间.
注意:Harry只能每次走到相邻的格子而不能斜走,每移动一次恰好为一分钟,并且Harry登上楼梯并经过楼梯到达对面的整个过程只需要一分钟,Harry从来不在楼梯上停留.并且每次楼梯都恰好在Harry移动完毕以后才改变方向.

[align=left]Sample Input[/align]

5 5
**..T
**.*.
..|..
.*.*.
S....


[align=left]Sample Output[/align]

7

Hint
Hint
地图如下:


[align=left]Source[/align]
Gardon-DYGG Contest 1

[align=left]Recommend[/align]
JGShining | We have carefully selected several similar problems for you: 1072 1026 1240 1253 1242
  
  bfs广搜。
  在广搜的基础框架之上加了一个“会旋转的楼梯”,楼梯有2个初始状态 “|” 和 “-” ,每移动一次楼梯就变化一次(| => - ; - => |)。每移动一次用时一分钟,如果遇到楼梯时,正好能通过,则直接跳到楼梯对面,时间+1(也就是说2个格子只用了1分钟);如果恰好不能通过,则在原地等待1分钟。问从初始位置(S)到终点(T)的最短时间。
  这道题的重点是遇到楼梯的处理,可以先用遇到楼梯时的步数(step)来判断,然后用遇到楼梯时的方向(i)来判断。
  处理方法如下:

  if   |    //遇到的楼梯初始是‘|’
    if  step是奇数,变化
      if  i 是奇数
        不能通过
      else
        能通过
    else  //不变
      if  i 是奇数
        能通过
      else
        不能通过
  if   -    //遇到的楼梯初始是‘-’
    if  step是奇数,变化
      if  i 是奇数
        能通过
      else
        不能通过
    else  //不变
      if  i 是奇数
        不能通过
      else
        能通过


另外注意两点:

  1.剪枝。有一个可以剪枝的地方:遇到楼梯先判断楼梯对面是否走过,如果已经走过,直接退出本次循环。

  2.超时问题。一定要处理好step(遇到楼梯时的步数),因为step是会变的,所以这次如果不能通过,下次也一定能通过。像我一开始把“step”整成了不会变的,测试结果对了,提交却一直超时。

[b]代码:[/b]

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
char a[21][21];
bool isw[21][21];
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
int M,N;
int startx,starty;
bool pass;    //能否通过梯子
struct NODE{
int x;
int y;
int step;
};
int abs(int n)
{
return n>0?n:-n;
}
bool judge(int x,int y,int i,int step)
{
if( x<1 || y<1 || x>M ||y>N )    //越界
return 1;
if( isw[x][y] )        //走过了
return 1;
if( a[x][y]=='*' )    //遇到墙
return 1;
if( a[x][y]=='|' ){
if( isw[x+dx[i]][y+dy[i]] )
return 1;
if( step%2 ){    //奇,变
if( i%2 )    //奇数
pass = false;    //不可以通过
else
pass = true;    //可以通过
}
else {    //不变
if( i%2 )    //奇数
pass = true;    //可以通过
else
pass = false;    //不可以通过
}
}
else if( a[x][y]=='-' ){
if( isw[x+dx[i]][y+dy[i]] )
return 1;
if( step%2 ){    //奇,变
if( i%2 )    //奇数
pass = true;    //可以通过
else
pass = false;    //不可以通过
}
else{    //不变
if( i%2 )    //奇数
pass = false;    //不可以通过
else
pass = true;    //可以通过
}
}
return 0;
}
int bfs(int x,int y)
{
queue <NODE> q;
NODE cur,next;
cur.x = x;
cur.y = y;
cur.step = 0;
q.push(cur);    //第一个节点入队
while(!q.empty()){
//队首出队
cur = q.front();
q.pop();
if(a[cur.x][cur.y]=='T')    //如果这一步已经走到了终点,则输出走到这一步的步数
return cur.step;
for(int i=0;i<4;i++){    //下一层节点入队
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if( judge(nx,ny,i,cur.step) )    //判定这一步可走否
continue;
if(a[nx][ny]=='|' || a[nx][ny]=='-'){    //如果这一步是碰到梯子的
if(pass){    //可以通过梯子
nx += dx[i];
ny += dy[i];
}
else{    //不可以通过梯子
nx -= dx[i];
ny -= dy[i];
}
}
next.x = nx;    //可走,记录下一步的位置
next.y = ny;
next.step = cur.step + 1;    //可走,步数累加
isw[next.x][next.y] = true;    //可走,标记走过
q.push(next);
}
}
}
int main()
{
while(cin>>M>>N){
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++){
cin>>a[i][j];
if(a[i][j]=='S'){
startx = i;
starty = j;
}
}
memset(isw,0,sizeof(isw));
isw[startx][starty] = true;
cout<<bfs(startx,starty)<<endl;
}
return 0;
}


Freecode : www.cnblogs.com/yym2013
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: