• BZOJ 1020 安全的航线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
     
    吐槽:不得不说这种计算几何题TTM恶心了,对着数据(70个点用geogebra一一手打)调了3天。功夫不负有心人,还是切掉了。感谢我们学校的大神犇莫涛学长的算法,不然像我这种蒟蒻恐怕一辈子都写不出二分答案的正解。
     
    为了表示膜拜,我将我的做法口述一遍吧(其实就是莫涛学长在论文上写的那种迭代),忽然间感觉自己和ydc比起来写得好丑。
    1. 先将所有不在多边形内部的线段加入队列中;
    2. 取出队首线段,找出与左端点最近的多边形上的点p1,右端点最近的多边形上的点p2。ans = max(ans,dis(p1,左端点),dis(p2,右端点));
    3. 在线段上二分出一个点p,使得dis(p,p1) == dis(p,p2);
    4. 若dis(p,p1) < ans,continue;否则,将线段二等分加入队列中;
    5. 重复2,3,4直到队列为空;

    算法(减枝)就是这样。为什么这样是对的呢?我们证明一下:

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

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

    有三种情况

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

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

    (注:上述证明转自:http://www.cnblogs.com/Randolph87/p/3642917.html)

    最后再贴一份自己丑丑的代码:

      1 #include<algorithm>
      2 #include<cmath>
      3 #include<queue>
      4 #include<cstdio>
      5 #include<cstdlib>
      6 #include<iostream>
      7 using namespace std;
      8 
      9 #define rhl 10001
     10 #define esp (1e-4)
     11 #define maxn (30)
     12 #define maxc (30)
     13 #define maxm (40)
     14 int tot,n,c,have[maxc]; double ans;
     15 
     16 inline double equal(double a,double b) { return fabs(a-b) < esp; }
     17 
     18 inline bool dd(double a,double b) { if (equal(a,b)) return true; return a >= b; }  //>=
     19 
     20 inline bool xd(double a,double b) { if (equal(a,b)) return true; return a <= b; }  //<=
     21 
     22 struct NODE
     23 {
     24     double x,y;
     25     friend inline bool operator == (NODE a,NODE b) { return equal(a.x,b.x)&&equal(a.y,b.y); }
     26     friend inline bool operator < (NODE a,NODE b)
     27     {
     28         if (a.x != b.x) return a.x < b.x;
     29         else return a.y < b.y;
     30     }
     31     inline NODE ra()
     32     {
     33         int xx,yy;
     34         do xx = rand()%rhl,yy = rand()%rhl;
     35         while (equal(1.0*xx,x)||equal(1.0*yy,y));
     36         return (NODE) {1.0*xx,1.0*yy};
     37     }
     38     inline void read() { scanf("%lf %lf",&x,&y); }
     39 }pol[maxc][maxm],bac[maxc*maxm];
     40 struct LINE
     41 {
     42     double a,b,c;
     43     friend inline bool operator ==(LINE l1,LINE l2) { return equal(l1.a*l2.c,l2.a*l1.c); }
     44     inline LINE vert(NODE p) { return (LINE) {b,-a,a*p.y-b*p.x}; }
     45     inline bool on(NODE p) { return equal(0,a*p.x+b*p.y+c); }
     46 };
     47 struct SEG{
     48     NODE a,b;
     49     inline NODE MID() { return (NODE) {(a.x+b.x)/2,(a.y + b.y)/2}; }
     50     inline bool exist() { return !(a == b); }
     51     inline LINE extend() { return (LINE) {a.y-b.y,b.x-a.x,b.y*(a.x-b.x)-b.x*(a.y-b.y)}; }
     52     inline bool on(NODE p)
     53     {
     54         if (p == a) return true;
     55         if (p == b) return true;
     56         return (dd(p.x,min(a.x,b.x))&xd(p.x,max(a.x,b.x)))&&(dd(p.y,min(a.y,b.y))&xd(p.y,max(a.y,b.y)));
     57     }
     58 }temp[maxn];
     59 queue <SEG> team;
     60 
     61 inline bool para(LINE l1,LINE l2) { return equal(l1.a * l2.b,l1.b * l2.a); }
     62 
     63 inline double qua(double a) { return a * a; }
     64 
     65 inline double dis(NODE a,NODE b) { return sqrt(qua(a.x - b.x)+qua(a.y - b.y)); }
     66 
     67 inline NODE cp(LINE l1,LINE l2)
     68 {
     69     double a1 = l1.a,b1 = l1.b,c1 = l1.c;
     70     double a2 = l2.a,b2 = l2.b,c2 = l2.c;
     71     double ry = (c2*a1-c1*a2)/(b1*a2-b2*a1),rx = (c1*b2-c2*b1)/(b1*a2-b2*a1);
     72     return (NODE) {rx,ry};
     73 }
     74 
     75 inline void cross(SEG s,int now)
     76 {
     77     LINE l = s.extend(),l1; SEG t; NODE p; NODE tt[maxm];
     78     int cnt = 0;
     79     for (int i = 1;i <= have[now];++i)
     80     {
     81         t = (SEG) {pol[now][i],pol[now][i-1]};
     82         l1 = t.extend();
     83         if (para(l,l1))
     84         {
     85             if (l == l1)
     86             {
     87                 if (s.on(t.a)) tt[++cnt] = t.a;
     88                 if (s.on(t.b)) tt[++cnt] = t.b;
     89             }
     90             continue;
     91         }
     92         p = cp(l,l1);
     93         if (t.on(p) && s.on(p))
     94             tt[++cnt] = p;
     95     }
     96     sort(tt+1,tt+cnt+1);
     97     for (int i = 1;i <= cnt;++i) bac[++tot] = tt[i];
     98 }
     99 
    100 inline NODE find(NODE p)
    101 {
    102     NODE ret,q; LINE l1,l2; SEG s; double best = 1e9,len;
    103     for (int i = 1;i <= c;++i)
    104         for (int j = 1;j <= have[i];++j)
    105         {
    106             s = (SEG) {pol[i][j],pol[i][j-1]};
    107             l1 = s.extend();
    108             l2 = l1.vert(p);
    109             q = cp(l1,l2);
    110             if (s.on(q))
    111             {
    112                 len = dis(p,q);
    113                 if (best > len) ret = q,best = len;
    114             }
    115             else
    116             {
    117                 if (dis(p,s.a) < dis(p,s.b)) q = s.a;
    118                 else q = s.b;
    119                 len = dis(p,q);
    120                 if (best > len) ret = q,best = len;
    121             }
    122         }
    123     return ret;
    124 }
    125 
    126 inline bool in(NODE p)
    127 {
    128     NODE q = p.ra(); SEG s = (SEG) {p,q},t; LINE l = s.extend(),l1; int cnt;
    129     for (int i = 1;i <= c;++i)
    130     {
    131         cnt = 0;
    132         for (int j = 1;j <= have[i];++j)
    133         {
    134             t = (SEG) {pol[i][j],pol[i][j-1]};
    135             if ((t.extend()).on(p)&&t.on(p)) return false;
    136             l1 = t.extend();
    137             if (para(l,l1)) continue;
    138             q = cp(l,l1);
    139             if (dd(q.x,p.x)&&t.on(q)) ++cnt;
    140         }
    141         if (cnt & 1) return true;
    142     }
    143     return false;
    144 }
    145 
    146 inline void init()
    147 {
    148     for (int i = 1;i < n;++i)
    149     {
    150         tot = 0;
    151         if (!(temp[i].a < temp[i].b)) swap(temp[i].a,temp[i].b);
    152         for (int j = 1;j <= c;++j)
    153             cross(temp[i],j);
    154         if (!in(temp[i].a)) bac[++tot] = temp[i].a;
    155         if (!in(temp[i].b)) bac[++tot] = temp[i].b;
    156         sort(bac+1,bac+tot+1);
    157         for (int j = 1;j < tot;j++)
    158             if (!in((SEG){bac[j],bac[j+1]}.MID()))
    159                 team.push((SEG){bac[j],bac[j+1]});
    160      }
    161 }
    162 
    163 inline void work()
    164 {
    165     SEG now; NODE mid,p1,p2,l,r; double ret;
    166     while (!team.empty())
    167     {
    168         now = team.front(); team.pop();
    169         if (!now.exist()) continue;
    170         p1 = find(now.a); p2 = find(now.b);
    171         l = now.a,r = now.b;
    172         while (!(l == r))
    173         {
    174             mid = ((SEG){l,r}).MID();
    175             if (dis(p1,mid) > dis(p2,mid)) r = mid;
    176             else l = mid;
    177         }
    178         ret = dis(r,p1);
    179         ans = max(max(dis(now.a,p1),dis(now.b,p2)),ans);
    180         if (ret-esp < ans) continue;
    181         mid = now.MID();
    182         team.push((SEG){now.a,mid}),team.push((SEG){mid,now.b});
    183     }
    184 }
    185 
    186 int main()
    187 {
    188     srand(233);
    189     ans = 0;
    190     scanf("%d %d ",&c,&n);
    191     NODE p1,p2; p1.read();
    192     for (int i = 2;i <= n;++i)
    193     {
    194         p2.read(); temp[i-1] = (SEG) {p1,p2};
    195         p1 = p2;
    196     }
    197     for (int i = 1;i <= c;++i)
    198     {
    199         scanf("%d ",have+i);
    200         for (int j = 1;j <= have[i];++j) pol[i][j].read();
    201         pol[i][0] = pol[i][have[i]];
    202     }
    203     init();
    204     work();
    205     printf("%.2lf
    ",ans);
    206     fclose(stdin); fclose(stdout);
    207     return 0;
    208 }
    View Code
    高考结束,重新回归。
  • 相关阅读:
    git分支管理之创建与合并分支
    git分支管理
    git远程仓库之从远程库克隆
    git远程仓库之添加远程库
    git远程仓库
    Git时光机穿梭之删除文件
    Git时光机穿梭之撤销修改
    Git时光机穿梭之管理修改
    Git时光机穿梭之工作区和暂存区
    Git时光机穿梭之版本回退
  • 原文地址:https://www.cnblogs.com/mmlz/p/4211827.html
Copyright © 2020-2023  润新知