• [二分][排序] JZOJ P1792 教主的花园


    Description

    【问题背景】
      LHX教主最近总困扰于前来膜拜他的人太多了,所以他给他的花园加上了一道屏障。 

    【问题描述】
      可以把教主的花园附近区域抽像成一个正方形网格组成的网络,每个网格都对应了一个坐标(均为整数,有可能为负),若两个网格(x1, y1),(x2, y2)有|x1 – x2| + |y1 – y2| = 1,则说这两个网格是相邻的,否则不是相邻的。
      教主在y = 0处整条直线上的网格设置了一道屏障,即所有坐标为(x, 0)的网格。当然,他还要解决他自己与内部人员的进出问题,这样教主设置了N个入口a1, a2, …, aN可供进出,即对于y = 0上的所有网格,只有 (a1, 0),(a2, 0), ……, (aN, 0) 可以通过,之外的所有纵坐标为0的网格均不能通过,而对于(x, y)有y不为0的网格可以认为是随意通过的。
      现在教主想知道,给定M个点对(x1, y1),(x2, y2),并且这些点均不在屏障上,询问从一个点走到另一个点最短距离是多少,每次只能从一个格子走到相邻的格子。
     

    Input

      输入的第1行为一个正整数N,为屏障上入口的个数。
      第2行有N个整数,a1, a2, …, aN,之间用空格隔开,为这N个入口的横坐标。
      第3行为一个正整数M,表示了M个询问。
      接下来M行,每行4个整数x1, y1, x2, y2,有y1与y2均不等于0,表示了一个询问从(x1, y1)到(x2, y2)的最短路。

    Output

      输出共包含m行,第i行对于第i个询问输出从(x1, y1)到(x2, y2)的最短路距离是多少。
     

    Sample Input

    2
    2 -1
    2
    0 1 0 -1
    1 1 2 2
    

    Sample Output

    4
    2 

    Hint

    【数据规模】
      对于20%的数据,有n,m≤10,ai,xi,yi绝对值不超过100;
      对于40%的数据,有n,m≤100,ai,xi,yi绝对值不超过1000;
      对于60%的数据,有n,m≤1000,ai,xi,yi绝对值不超过100000;
      对于100%的数据,有n,m≤100000,ai,xi,yi绝对值不超过100000000。

    题解

    • 题目大意就是在一个平面直角坐标系中x轴上是一道屏障,但上面有n个开头,要求两个点的距离
    • 显然,这题可以分类讨论来做
    • ①两个点的y坐标同号,直接求曼哈顿距离输出
    • 如果不行,则二分一个在中间的开口
    • ②如果这个开口位于两个点中间,求出两个点分别到开口的曼哈顿距离相加并输出
    • ③否则判断一下它距离哪一个端点近,就由哪里绕过去
    •     虽然此时的pos值不一定准确,但十分接近,真实值一定出现在pos-1,pos,pos+1中,求最小值输出就好了

    代码

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 using namespace std;
     5 int n,m,a[100010];
     6 int abs(int a){ return a<0?-a:a;}
     7 int find(int x)
     8 {
     9     int l=1,r=n,k=n;
    10     while(l<=r)
    11     {
    12         int mid=(l+r)/2;
    13         if(a[mid]<x) l=mid+1; else r=mid-1,k=mid;
    14     }
    15     return k;
    16 } 
    17 int main()
    18 {
    19     int x1,x2,y1,y2;
    20     scanf("%d",&n);
    21     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    22     sort(a+1,a+n+1);
    23     scanf("%d",&m);
    24     for(int i=1;i<=m;i++)
    25     {
    26         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    27         if((y1<0&&y2<0)||(y1>0&&y2>0))
    28         {
    29             printf("%d
    ",abs(y1-y2)+abs(x1-x2));
    30             continue;
    31         }
    32         if(x1>x2) swap(x1,x2);
    33         int pos=find((x1+x2)/2);
    34         if(a[pos]>=x1&&a[pos]<=x2 )printf("%d
    ",abs(y1-y2)+abs(x1-x2));
    35         else
    36         {
    37             int t1=abs(a[pos]-x1)+abs(a[pos]-x2)+abs(y1-y2),t2=0x7fffffff,t3=0x7fffffff;
    38             if(pos>1) t2=abs(a[pos-1]-x1)+abs(a[pos-1]-x2)+abs(y1-y2);
    39             if(pos<n) t3=abs(a[pos+1]-x1)+abs(a[pos+1]-x2)+abs(y1-y2);
    40             if(t1>t2) t1=t2;
    41             if(t1>t3) t1=t3;
    42             printf("%d
    ",t1);
    43         }
    44     }
    45 }
  • 相关阅读:
    mysql常用语句集锦
    PHP 面向对象
    PHP 数组
    PHP 语句 函数 字符串处理
    PHP 随笔
    mysql常用函数
    数据库 创建 查询 练习
    HTML JavaScript语法练习
    HTML JavaScript练习
    随机数生成的简单原理
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8427180.html
Copyright © 2020-2023  润新知