海底总动员

描述

尼莫是一个顽皮的男孩。有一天,他独自进入了深海。不幸的是,他迷路了,找不到回家的路。因此,他向他父亲马林发出了一个信号,要求他帮忙。 
检查地图后,马林发现大海就像一个有墙壁和门的迷宫。所有壁都平行于X轴或Y轴。假设壁的厚度为零。 
所有的门都在墙上打开,长度为1.除非墙上有门,否则马林不能通过墙。因为通过一扇门是危险的(门附近可能有一些恶毒的medusas),Marlin想要通过尽可能少的门来找到Nemo。 
图1显示了迷宫的一个例子以及Marlin找到Nemo的路径。 


我们假设Marlin的初始位置是(0,0)。鉴于Nemo的位置以及墙壁和门的配置,请编写一个程序来计算Marlin为达到Nemo而必须经过的最小门数。

输入

输入包含几个测试用例。每个测试用例由两个非负整数M和N开始.M表示迷宫中的墙数,N表示门的数量。 
然后跟随M行,每行包含四个以下列格式描述墙的整数: 
xydt 
(x,y)表示墙的左下角,d是墙的方向 - 0表示它与X平行-axis和1表示它与Y轴平行,t表示墙的长度。 
任何墙的两端坐标将在[1,199]范围内。 
然后有N行描述门: 
xyd 
x,y,d与墙具有相同的含义。由于门的固定长度为1,因此省略了t。 
每个案例的最后一行包含两个正浮点数: 
f1 f2 
(f1,f2)给出了Nemo的位置。它不会位于任何墙壁或门内。 
M = -1且N = -1的测试用例表示输入结束,不应进行处理。

产量

对于每个测试用例,请在单独的一行中输出Marlin必须经过的最小门数才能营救他的儿子。如果他不能到达N​​emo,输出-1。

Sample Input

8 9
1 1 1 3
2 1 1 3
3 1 1 3
4 1 1 3
1 1 0 3
1 2 0 3
1 3 0 3
1 4 0 3
2 1 1
2 2 1
2 3 1
3 1 1
3 2 1
3 3 1
1 2 0
3 3 0
4 3 1
1.5 1.5
4 0
1 1 0 1
1 1 1 1
2 1 1 1
1 2 0 1
1.5 1.7
-1 -1

Sample Output

5
-1

建图方法有点麻烦,把墙和门设作坐标点的属性,

循环队列进行广搜,每次循环四个方向

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <queue>
#define N 201
#define inf 0x3f3f3f3f
using namespace std;
struct node
{
    int step;   //记录穿过的门数
    int f[4];   //0,1,2,3 表示上下左右四个边
} a[N][N];
bool v[N][N];
int xx[]= {0,0,-1,1};  //上下左右
int yy[]= {1,-1,0,0};
void bfs(int x,int y)
{
    queue<pair<int,int> >q;
    q.push(pair<int ,int >(x,y));
    a[x][y].step=0;
    v[x][y]=true;
    while(!q.empty())
    {
        x=q.front().first;
        y=q.front().second;
        q.pop();
        for(int i=0; i<4; i++)
        {
            int s=x+xx[i];   //上下左右
            int e=y+yy[i];
            if(s<1 || e<1 ||s>199 || e>199) continue;
            if(a[x][y].f[i]==-1)    //表示方向上出去了
            {
                printf("%d\n",a[x][y].step);
                return ;
            }
            if(!v[s][e] && a[x][y].f[i]==0)  //过门
            {
                v[s][e]=true;
                a[s][e].step=a[x][y].step+1;
                q.push(pair<int, int>(s,e));
            }
        }
    }
    printf("-1\n");
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==-1 && m==-1) break;

        for(int i=0; i<N; i++)
        {
            for(int j=0; j<N; j++)
            {
                a[i][j].f[0]=-1;
                a[i][j].f[1]=-1;
                a[i][j].f[2]=-1;
                a[i][j].f[3]=-1;
                a[i][j].step=0;
            }
        }
        while(n--)  //墙
        {
            int x,y,d,t;
            scanf("%d%d%d%d",&x,&y,&d,&t);    //格子左下角的坐标标记整个格子
            if(d)             // 墙与y轴平行
            {
                for(int i=0; i<t; i++)
                {
                    a[x][y+i].f[2]=1;      //点(x,y)向上t格的左边标记为墙
                    if(x>1)                //当横坐标为1的时候,左面没有格子
                        a[x-1][y+i].f[3]=1;   //点(x,y)左面的格子(x-1,y)的右面标记为墙
                }
            }
            else              //墙与x轴平行
            {
                for(int i=0; i<t; i++)
                {
                    a[x+i][y].f[1]=1;      //点(x,y)向右t格的下边标记为墙
                    if(y>1)                //当纵坐标为1的时候,下面没有格子
                        a[x+i][y-1].f[0]=1;  //点(x,y)下面的格子(x,y-1)的上面标记为墙
                }
            }
        }
        while(m--)           //门,同墙
        {
            int x,y,d;
            scanf("%d%d%d",&x,&y,&d);
            if(d)
            {
                a[x][y].f[2]=0;
                if(x>1)
                    a[x-1][y].f[3]=0;
            }
            else
            {
                a[x][y].f[1]=0;
                if(y>1)
                    a[x][y-1].f[0]=0;
            }
        }
        double s,e;
        memset(v,false,sizeof(v));
        cin>>s>>e;
        if( s<1 || s>199 || e<1 || e>199)    //没有这个会RE    ,  死孩子在外面的时候
        {
            printf("0\n");
            continue;
        }
        bfs((int)s,int(e));
    }
    return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值