FZU 2235 国王的出游【离散化+Bfs】

224 篇文章 2 订阅

 Problem 2235 国王的出游

Accept: 49    Submit: 260
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

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

思路(思路代码参考自:http://blog.csdn.net/tc_to_top/article/details/51567161):


就是考验代码能力的一道题。

然而直接Map+排序,分成行和列去离散化的话,FZU没有开O2加速,Map会一直TLE...............................

所以我们不妨换个思路。

我们用pair存入所有点,因为点的个数不超过1e5.所以我们对线段所覆盖的点去重并存入即可。

然后我们直接将每个点拿出,看看其周围8个位子是否能走,如果有能走的地方,直接建一条边就行。

然后跑一下Bfs就行了。


Ac代码:

/*
    代码参考自:http://blog.csdn.net/tc_to_top/article/details/51567161
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct node
{
    int from;
    int to;
    int next;
}e[105000*8];
int cont;
int head[105000];
int dist[105000];
int fx[8]={0,0,1,-1,-1,1,-1,1};
int fy[8]={1,-1,0,0,-1,1,1,-1};
pair<int ,int >p[105000];
int cnt;
int sx,sy,ex,ey;
void add(int from,int to)
{
    e[cont].to=to;
    e[cont].next=head[from];
    head[from]=cont++;
}
void SPFA()
{
    for(int i=1;i<=cnt;i++)dist[i]=0x3f3f3f3f;
    int ss=lower_bound(p+1,p+1+cnt,make_pair(sx,sy))-p;
    int tt=lower_bound(p+1,p+1+cnt,make_pair(ex,ey))-p;
    dist[ss]=0;
    queue<int>s;
    s.push(ss);
    while(!s.empty())
    {
        int u=s.front();
        s.pop();
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            if(dist[v]>dist[u]+1)
            {
                dist[v]=dist[u]+1;
                s.push(v);
            }
        }
    }
    if(dist[tt]==0x3f3f3f3f)printf("-1\n");
    else printf("%d\n",dist[tt]);
}
int main()
{
    while(~scanf("%d%d%d%d",&sx,&sy,&ex,&ey))
    {
        cnt=0;
        cont=0;
        int tot;
        scanf("%d",&tot);
        memset(head,-1,sizeof(head));
        for(int i=0;i<tot;i++)
        {
            int h,l,r;
            scanf("%d%d%d",&h,&l,&r);
            for(int j=l;j<=r;j++)
            {
                p[++cnt]=make_pair(h,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++)
            {
                pair<int ,int >now=make_pair(p[i].first+fx[j],p[i].second+fy[j]);
                int pos=lower_bound(p+1,p+cnt+1,now)-p;
                if(p[pos].first==p[i].first+fx[j]&&p[pos].second==p[i].second+fy[j])
                {
                    add(i,pos);
                }
            }
        }
        SPFA();
    }
}








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值