HDU 1180 (诡异的楼梯)+HDU 2102 (A计划)

之前自己也写过这两题,但是感觉真是神坑,不管怎么都过不了。今天巍神开了专题后又有这两题,于是我就开始认真写和debug。竟然AC了好开心。来总结下坑点。


诡异的楼梯
题意: S是起点,T是终点,*是障碍物,| 和 — 是楼梯。楼梯很特别,每隔一秒换一个方向。人可以停留在任意一个点上,但是不能停留在楼梯上。
解题方法: 利用BFS优先队列。有一点需要注意的是当你走到楼梯口时,从楼梯这边到楼梯那边只需要一秒的时间,且如果楼梯方向与你的行走方向不一致的时候,你可以在原地等一秒钟让楼梯换了方向再过去。还有就是可能楼梯对面就是终点,也可能是障碍物。
HDU上的数据很水,我感觉我是水过的。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 20+5;
struct Node
{
    int x,y,cnt;
    friend bool operator <(const Node a ,const Node b)
    {
        return a.cnt > b.cnt;
    }
};
int dir[4][2]={0,1,1,0,0,-1,-1,0};
bool vis[N][N];
char Map[N][N];
int n,m;
bool check(int x,int y)
{
    if(x<1||x>n) return false;
    if(y<1||y>m) return false;
    if(!vis[x][y]) return false;
    if(Map[x][y]=='*') return false;
    else return true;
}
bool judge(int x,int y,int i,int cnt)//判断这个楼梯是否可以现在通过
{
    if(cnt%2)
    {
        if(Map[x][y]=='|')
        {
            if(i==0||i==2) return true;
            else return false;
        }
        if(Map[x][y]=='-')
        {
            if(i==1||i==3) return true;
            else return false;
        }
    }
    else
    {
        if(Map[x][y]=='-')
        {
            if(i==0||i==2) return true;
            else return false;
        }
        if(Map[x][y]=='|')
        {
            if(i==1||i==3) return true;
            else return false;
        }
    }
}
int bfs(int x,int y)
{
    Node now,next;
    priority_queue<Node> que;
    now.x=x;
    now.y=y;
    now.cnt=0;
    vis[now.x][now.y]=false;
    que.push(now);
    while(!que.empty())
    {
        now=que.top();
        que.pop();
        if(Map[now.x][now.y]=='T') return now.cnt;

        for(int i=0;i<4;i++)
        {
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];

            if(!check(next.x,next.y)) continue;
            if(Map[next.x][next.y]!='|'&&Map[next.x][next.y]!='-')//两种情况分开讨论
            {
                next.cnt=now.cnt+1;
                vis[next.x][next.y]=false;
                que.push(next);
            }
            else
            {
                if(!judge(next.x,next.y,i,now.cnt)) next.cnt=now.cnt+2;
                else  next.cnt=now.cnt+1;

                next.x+=dir[i][0];
                next.y+=dir[i][1];
                if(!check(next.x,next.y)) continue;
                vis[next.x][next.y]=false;
                que.push(next);
            }
        }
    }
    return -1;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int x,y;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf(" %c",&Map[i][j]);
            if(Map[i][j]=='S')
            x=i,y=j;
        }
        memset(vis,true,sizeof(vis));
        printf("%d\n",bfs(x,y));
    }
    return 0;
}

A计划

题意: 两层的地图,S是起点,P是终点。#是时空传输机,*是障碍物。
解题思路: 同样是BFS优先队列。

  • 起点和终点有可能在同一层
  • 遇到传输机的时候必须传输,没有第二种选择
  • 当传输过去是墙,直接撞死
  • 当传输机的对面也是传输机的时候,然会就会在两层之间反复传输,得不出结果

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
struct Node
{
    int x,y,z,cnt;
    friend bool operator < (const Node a,const Node b)
    {
        return a.cnt > b.cnt;
    }
};
int n,m,T;
const int N = 12;
char Map[2][N][N];
bool vis[2][N][N];
bool bfs(int x,int y ,int z)
{
    Node now,next;
    priority_queue<Node>  que;
    now.z=z;
    now.x=x;
    now.y=y;
    now.cnt=0;
    vis[z][x][y]=false;
    que.push(now);
    while(!que.empty())
    {

        now=que.top();
        que.pop();
        if(Map[now.z][now.x][now.y]=='P'&&now.cnt<=T) return true;
        if(now.cnt>T) return false;

        for(int i=0;i<4;i++)
        {
            next.z=now.z;
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];
            if(next.x<1||next.x>n) continue;
            if(next.y<1||next.y>m) continue;
            if(!vis[next.z][next.x][next.y]) continue;
            if(Map[next.z][next.x][next.y]=='#')
            {
                vis[next.z][next.x][next.y]=false;
                if(next.z) next.z=0;
                else next.z=1;
                if(Map[next.z][next.x][next.y]=='#') continue;//传输过去也是传输机的时候
            }
            if(Map[next.z][next.x][next.y]=='*') continue;//传输过去是墙的时候
            if(!vis[next.z][next.x][next.y]) continue;
            vis[next.z][next.x][next.y]=false;
            next.cnt=now.cnt+1;
            que.push(next);
        }
    }
   return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n,&m,&T);
        int x,y,z;
        for(int k=0;k<2;k++)
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf(" %c",&Map[k][i][j]);
            if(Map[k][i][j]=='S') x=i,y=j,z=k;
        }
        memset(vis,true,sizeof(vis));
        puts(bfs(x,y,z)?"YES":"NO");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值