hdu 1180 诡异的楼梯(bfs+最短路+dp)

题意:

给定一个n*m的地图,给定了起点S和终点T。

某些格子上有障碍,有些格子上有楼梯。

有障碍的格子不能走,有楼梯的格子只有楼梯的方向跟行进方向相同时才能走。

楼梯每分钟变换一次方向(横向或竖向)。

每走一步花费1分钟,走楼梯的话可以直接走到楼梯对面,也是花费一分钟。

没有两个相邻的楼梯,人不能在楼梯上停留。

求需花费的最小时间。


算法:

按时间的奇偶性拆点,距离保存两个量,分别对应时间是奇数和时间是偶数时。

队列中的点具有时间上的单调性。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define st first
#define nd second
#define mp make_pair

using namespace std;

typedef pair<int,int> PII;//<pos,state> state表示时间的奇偶
int mm[25][25];
int d[25][25][2]; //d[x][y][state]
queue<PII> q;
int m,n,S,T;

int dx[]={1,-1,0,0,0};
int dy[]={0,0,1,-1,0};//注意考虑原地不动的情况

int get_id(int x,int y)
{
    return (x-1)*m+y-1;
}

int main()
{
    char str[25];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(d,-1,sizeof(d));
        memset(mm,-1,sizeof(mm));

        for(int i=0;i<n;i++)
        {
            scanf("%s",str);
            for(int j=0;j<m;j++)
            {
                if(str[j]=='|')
                    mm[i+1][j+1]=0;
                else if(str[j]=='-')
                    mm[i+1][j+1]=1;
                else if(str[j]=='.')
                    mm[i+1][j+1]=2;
                else if(str[j]=='S')
                {
                    mm[i+1][j+1]=2;
                    S = get_id(i+1,j+1);
                }
                else if(str[j]=='T')
                {
                    mm[i+1][j+1]=2;
                    T = get_id(i+1,j+1);
                }
            }
        }

        while(!q.empty())
            q.pop();

        d[S/m+1][S%m+1][0]=0;
        q.push(mp(S,0));
        while(!q.empty())
        {
            int x = q.front().st;
            if(x==T)
                break;

            int y = x%m+1;
            x = x/m+1;

            int state = q.front().nd;
            q.pop();

            //cout<<x<<' '<<y<<' '<<state<<endl;
            for(int i=0;i<5;i++)
            {
                int nx = x+dx[i];
                int ny = y+dy[i];
                if(mm[nx][ny]==-1)
                {
                    continue;
                }
                if(mm[nx][ny]<2 && ((mm[nx][ny]^state)==(i>>1)))  //判断是否是楼梯在此时刻是否刚好变为和要走的方向相同
                {
                    nx+=dx[i];
                    ny+=dy[i];
                }
                else if(mm[nx][ny]<2 && ((mm[nx][ny]^state)!=(i>>1)))
                {
                    continue;
                }
                if(mm[nx][ny]==-1)  //判断通过楼梯后的那块地是否可以走
                {
                    continue;
                }
                if(d[nx][ny][state^1]==-1 || d[nx][ny][state^1]>d[x][y][state]+1)//最短路更新
                {
                    d[nx][ny][state^1]=d[x][y][state]+1;
                    int tmp = get_id(nx,ny);
                    q.push(mp(tmp,state^1));
                }
            }
        }
        if(d[T/m+1][T%m+1][0]!=-1 && d[T/m+1][T%m+1][1]!=-1){
            printf("%d\n",min(d[T/m+1][T%m+1][0],d[T/m+1][T%m+1][1])); //如果奇数时刻和偶数时刻都能走到
        }else{
            printf("%d\n",max(d[T/m+1][T%m+1][0],d[T/m+1][T%m+1][1])); //如果只有一个能走到必定走不到的还是为-1,所以较大值
        }
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值