zoukankan      html  css  js  c++  java
  • 1020: [SHOI2008]安全的航线flight

    Description

    在设计航线的时候,安全是一个很重要的问题。首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率。当飞机迫降到海上的时候,最近的陆地就是一个关键的因素。航线中最危险的地方就是距离最近的陆地最远的地方,我们称这种点为这条航线“孤地点”。孤地点到最近陆地的距离被称为“孤地距离”。作为航空公司的高级顾问,你接受的第一个任务就是尽量找出一条航线的孤地点,并计算这条航线的孤地距离。为了简化问题,我们认为地图是一个二维平面,陆地可以用多边形近似,飞行线路为一条折线。航线的起点和终点都在陆地上,但中间的转折点是可能在海上(如下图所示,方格标示出了孤地点)。
    Input

    输入的第一行包括两个整数C和N(1≤C≤20,2≤N≤20),分别代表陆地的数目的航线的转折点的数目。接下来有N行,每行有两个整数x,y。(x,y)表示一个航线转折点的坐标,第一个转折点为航线的起点,最后一个转折点为航线的终点。接下来的输入将用来描述C块大陆。每块输入由一个正整数M开始(M≤30),M表示多边形的顶点个数,接下来的M行,每行会包含两个整数x,y,(x,y)表示多边形的一个顶点坐标,我们保证这些顶点以顺时针或逆时针给出了该多边形的闭包,不会出现某些边相交的情况。此外我们也保证输入数据中任何两块大陆不会相交。输入的所有坐标将保证在-10000到10000的范围之间。
    Output

    输出一个浮点数,表示航线的孤地距离,数据保留2位小数。
    Sample Input
    1 2
    -9 -6
    5 1
    3
    0 16
    -16 -12
    17 -6
    Sample Output
    0.00

    原来的解法是二分答案,然后把陆地扩展,再判断是否覆盖了航线,但是太繁琐,我根本写不出来

    所以我用的是莫涛的那种解法

    没想到我竟然错在求垂足上,囧..........

    但是答案竟然正确了,时间变长了好多,查了好久才查出来

    1.初始化孤地点可能位于的线段集合为整条航线。
    2.对于长L的某条线段,左端点与陆地的最近点为P1,右端点与陆地的最近点为P2,那么该线段上的孤地距离将受P1与P2影响。具体来说,利用二分求出该线段上的点P使得dis(p1,p)=dis(p2,p)
    令r=dis(p1,p),若r小于已有的最优答案,那么可以删除该线段。(当然,这个只要r-0.001<ans就行了,只要精度达到了就行,不然就是死循环了)
    4.取所有线段的中点更新答案。
    5.将所有线段从中点分成左右两条线段。
    6.不断进行2,3,4直到线段的集合为空。

    这个做法效率很高,(哇,好开心,在BZOJ上是pascal第一)

    我们现在要讨论的就是这个算法的正确性

    现在我们有一条线段和对应的p1和p2,分别是左端点最近的点和右端点最近的点

    有三种情况

    然后我们发现线段上的点到自己最近点的距离不会超过max(dis(p1,p),dis(a,p1),(b,p2))(a,b分别为线段的左右端点)

    所以我们的删除操作是对的,我们删除的都是不会更新答案的线段,就像ydc说的一样,这个就像是搜索剪枝

    时间效率也很好,只是细节要注意,不要像我一样傻×,连求垂足都求错

      1 /**************************************************************
      2     Problem: 1020
      3     User: 1997cb
      4     Language: Pascal
      5     Result: Accepted
      6     Time:96 ms
      7     Memory:6488 kb
      8 ****************************************************************/
      9  
     10 const
     11     maxn=22;
     12     maxm=33;
     13     maxq=100000;
     14     eps=1e-16;
     15 type
     16     point=record
     17       x,y:double;
     18     end;
     19     polygon=record
     20       tot:longint;
     21       a:array[0..maxm]of point;
     22     end;
     23     seg=record
     24       a,b,neara,nearb:point;
     25     end;
     26 var
     27     c,head,tail:longint;
     28     ans:double;
     29     s:array[0..maxq]of seg;
     30     p:array[0..maxn]of polygon;
     31   
     32 function max(x,y:double):double;
     33 begin
     34     if x>y then exit(x);
     35     exit(y);
     36 end;
     37   
     38 function cj(x1,y1,x2,y2:double):double;
     39 begin
     40     exit(x1*y2-y1*x2);
     41 end;
     42   
     43 function on(var a,b,c:point):boolean;
     44 begin
     45     exit((abs(cj(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y))<=eps) and ((a.x-c.x)*(b.x-c.x)<=eps) and ((a.y-c.y)*(b.y-c.y)<=eps));
     46 end;
     47   
     48 function jiao(var a,b,c,d:point):boolean;
     49 begin
     50     exit((cj(b.x-a.x,b.y-a.y,d.x-a.x,d.y-a.y)*cj(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y)<=eps) and (cj(d.x-c.x,d.y-c.y,a.x-c.x,a.y-c.y)*cj(d.x-c.x,d.y-c.y,b.x-c.x,b.y-c.y)<=eps));
     51 end;
     52   
     53 function include(var a:polygon;var b:point):boolean;
     54 var
     55     i,tot:longint;
     56     k:point;
     57 begin
     58     for i:=1 to a.tot do
     59       if on(a.a[i],a.a[i mod a.tot+1],b) then exit(true);
     60     tot:=0;
     61     k.x:=-100000;
     62     k.y:=100000;
     63     for i:=1 to a.tot do
     64       if jiao(a.a[i],a.a[i mod a.tot+1],k,b) then inc(tot);
     65     if tot and 1=1 then exit(true);
     66     exit(false);
     67 end;
     68   
     69 procedure get(var near,a:point;var dis:double;var b,c:point);
     70 var
     71     d:double;
     72 begin
     73     if (c.x-b.x)*(a.x-b.x)+(c.y-b.y)*(a.y-b.y)<=eps then
     74     begin
     75       d:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
     76       if dis>d+eps then
     77       begin
     78         near:=b;
     79         dis:=d;
     80       end;
     81       exit;
     82     end;
     83     if (c.x-b.x)*(a.x-c.x)+(c.y-b.y)*(a.y-c.y)>=-eps then
     84     begin
     85       d:=sqrt(sqr(a.x-c.x)+sqr(a.y-c.y));
     86       if dis>d+eps then
     87       begin
     88         near:=c;
     89         dis:=d;
     90       end;
     91       exit;
     92     end;
     93     d:=cj(c.x-b.x,c.y-b.y,a.x-b.x,a.y-b.y)/sqrt(sqr(b.x-c.x)+sqr(b.y-c.y));
     94     if dis>abs(d)+eps then
     95     begin
     96       dis:=abs(d);
     97       near.x:=a.x+(c.y-b.y)*d/sqrt(sqr(b.x-c.x)+sqr(b.y-c.y));
     98       near.y:=a.y-(c.x-b.x)*d/sqrt(sqr(b.x-c.x)+sqr(b.y-c.y));
     99     end;
    100 end;
    101   
    102 procedure find(var a,b:point);
    103 var
    104     i,j:longint;
    105     dis:double;
    106 begin
    107     for i:=1 to c do
    108       if include(p[i],b) then
    109       begin
    110         a:=b;
    111         exit;
    112       end;
    113     dis:=1<<30;
    114     for i:=1 to c do
    115       for j:=1 to p[i].tot do
    116         get(a,b,dis,p[i].a[j],p[i].a[j mod p[i].tot+1]);
    117     ans:=max(ans,dis);
    118 end;
    119   
    120 procedure init;
    121 var
    122     i,j:longint;
    123 begin
    124     read(c,tail);
    125     head:=1;
    126     for i:=1 to tail do
    127       with s[i].a do
    128         read(x,y);
    129     for i:=1 to c do
    130       with p[i] do
    131         begin
    132           read(tot);
    133           for j:=1 to tot do
    134             with a[j] do
    135               read(x,y);
    136         end;
    137     for i:=1 to tail do
    138       with s[i] do
    139         find(neara,a);
    140     for i:=1 to tail-1 do
    141       begin
    142         s[i].b:=s[i+1].a;
    143         s[i].nearb:=s[i+1].neara;
    144       end;
    145 end;
    146   
    147 procedure work;
    148 var
    149     l,r,mid:point;
    150     d:double;
    151 begin
    152     while head<>tail do
    153       begin
    154         l:=s[head].a;
    155         r:=s[head].b;
    156         while (sqrt(sqr(l.x-r.x)+sqr(l.y-r.y))>1e-4) do
    157           begin
    158             mid.x:=(l.x+r.x)/2;
    159             mid.y:=(l.y+r.y)/2;
    160             with s[head] do
    161             if sqrt(sqr(mid.x-neara.x)+sqr(mid.y-neara.y))<sqrt(sqr(mid.x-nearb.x)+sqr(mid.y-nearb.y)) then l:=mid
    162             else r:=mid;
    163           end;
    164         with s[head] do
    165         d:=max(sqrt(sqr(l.x-neara.x)+sqr(l.y-neara.y)),sqrt(sqr(l.x-nearb.x)+sqr(l.y-nearb.y)));
    166         mid.x:=(s[head].a.x+s[head].b.x)/2;
    167         mid.y:=(s[head].a.y+s[head].b.y)/2;
    168         find(l,mid);
    169         if d>ans+0.001 then
    170         begin
    171           s[tail].a:=s[head].a;
    172           s[tail].b:=mid;
    173           s[tail].nearb:=l;
    174           s[tail].neara:=s[head].neara;
    175           tail:=tail mod maxq+1;
    176           s[tail].a:=mid;
    177           s[tail].b:=s[head].b;
    178           s[tail].neara:=l;
    179           s[tail].nearb:=s[head].nearb;
    180           tail:=tail mod maxq+1;
    181         end;
    182         head:=head mod maxq+1;
    183       end;
    184     write(ans:0:2);
    185 end;
    186   
    187 begin
    188     init;
    189     work;
    190 end.
    View Code
  • 相关阅读:
    python2和3使用pip时的问题
    Python爬虫-爬取百度贴吧帖子
    Python爬虫-爬取糗事百科段子
    keras例子-matchnet
    win10-Anaconda2-Theano-cuda7.5-VS2013
    caffe-win10-cifar10另
    PHP——0126最初
    PHP——动态随机数
    PHP——投票
    PHP——内测:联系人管理
  • 原文地址:https://www.cnblogs.com/Randolph87/p/3642917.html
Copyright © 2011-2022 走看看