FZU 2235 国王的出游 (离散化 + BFS)

129 篇文章 0 订阅
66 篇文章 0 订阅
 Problem 2235 国王的出游

Accept: 44    Submit: 235
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

黑暗之王有一片棋盘般的疆土,这片疆土有2*10^9行,有2*10^9列。假设这块疆土的行从上到下编号1到2*10^9,它的列从左到右也编号1到2*10^9。我们可以把第i行第j列的方格记为坐标(i,j)。

但是这偌大棋盘只有被给的N个线状区域才是允许通行的。每个线状区域被三个参数描述,ri,ai,bi(ai<= bi)。ri代表给定线状区域的行编号,ai代表线状区域的起始列编号,bi代表末尾编号。

现在国王想要从一个给定坐标方格(x0,y0)通过最小移动步数到达终点坐标方格(x1,y1),而且只能通过上述给出的允许通行的线状区域。

国王移动一步只能发生在相邻的方格之间。此外,如果两个方格至少共享一个点我们便认为他们相邻。

 Input

有多组数据(<=30),处理到文件尾(EOF)。

每组数据第一行包含四个整数,x0, y0, x1, y1(1 <= x0, y0, x1, y1 <= 2*10^9),分别代表国王的初始坐标和终点坐标。

第二行有一个整数N (1 <= N <= 10^5),代表有N条可通行的线状区域。

接下里会有N行,第i行包含三个整数,ri,ai, bi (1 <= ri, ai bi <= 2*10^9),含义看题面。

数据允许线状区域会有交叉或者嵌套。

数据保证国王的起点方格和终点方格都是可通行的,并且两个区域不相同。另外保证所有线状区域的的长度总和不超过10^5。

1 <= x0, y0, x1, y1, ri, ai, bi<= 2*10^9,1 <= N <= 10^5

 Output

如果没有一条道路使得国王从起始区域到达终点区域,则输出 -1。

否则,则输出国王的从起始区域到达终点区域的最小步数。

 Sample Input

5 7 6 11
3
5 3 8
6 7 11
5 2 5


1 1 2 10
2
1 1 3
2 6 10

 Sample Output

4
-1

 Source

福州大学第十三届程序设计竞赛


题目分析:感觉这题就是考离散化的。。。坐标范围这么大,点数这么小,直接对点去重再离散化,然后可走的两个点之间连边,BFS一下即可
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define X first
#define Y second
using namespace std;
int const MAX = 1e5 + 5;
int stx, sty, edx, edy, n, ecnt;
int head[MAX];
int st, ed;
int dx[8] = {1, 1, 1, -1, -1, -1, 0, 0};
int dy[8] = {0, 1, -1, 0, 1, -1, 1, -1};
bool vis[MAX];

pair <int, int> p[MAX], t;

struct EDGE
{
    int to, nxt;
}e[MAX << 3];

struct POINT
{
    int pos, step;
};

void Init()
{
    ecnt = 0;
    memset(head, -1, sizeof(head));
}

void Add(int u, int v)
{
    e[ecnt].to = v;
    e[ecnt].nxt = head[u];
    head[u] = ecnt ++;
}

int BFS()
{
    memset(vis, false, sizeof(vis));
    queue <POINT> q;
    POINT s;
    s.pos = st;
    s.step = 0;
    q.push(s);
    vis[st] = true;
    while(!q.empty())
    {
        POINT cur = q.front(), t;
        q.pop();
        if(cur.pos == ed)
            return cur.step;
        for(int i = head[cur.pos]; i != -1; i = e[i].nxt)
        {
            t.pos = e[i].to;
            t.step = cur.step + 1;
            if(!vis[t.pos])
            {
                vis[t.pos] = true;
                q.push(t);
            }
        }
    }
    return -1;
}

int main()
{
    while(scanf("%d %d %d %d", &stx, &sty, &edx, &edy) != EOF)
    {
        Init();
        int cnt = 1, x, y1, y2;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d %d %d", &x, &y1, &y2);
            for(int j = y1; j <= y2; j++)
                p[cnt ++] = make_pair(x, j);
        }
        sort(p + 1, p + cnt + 1);
        cnt = unique(p + 1, p + cnt + 1) - p - 1;
        for(int i = 1; i <= cnt; i++)
        {
            for(int j = 0; j < 8; j++)
            {
                t = make_pair(p[i].X + dx[j], p[i].Y + dy[j]);
                int pos = lower_bound(p + 1, p + cnt + 1, t) - p;
                if(p[pos].X == p[i].X + dx[j] && p[pos].Y == p[i].Y + dy[j])
                    Add(i, pos);
            }
        }
        st = lower_bound(p + 1, p + cnt + 1, make_pair(stx, sty)) - p;
        ed = lower_bound(p + 1, p + cnt + 1, make_pair(edx, edy)) - p;
        printf("%d\n", BFS());
    }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值