HDU 1180 诡异的楼梯(BFS+状态选择)

诡异的楼梯

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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值