zoukankan      html  css  js  c++  java
  • POJ 3608 凸包间最短距离(旋转卡壳)

    Bridge Across Islands
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 11539   Accepted: 3395   Special Judge

    Description

    Thousands of thousands years ago there was a small kingdom located in the middle of the Pacific Ocean. The territory of the kingdom consists two separated islands. Due to the impact of the ocean current, the shapes of both the islands became convex polygons. The king of the kingdom wanted to establish a bridge to connect the two islands. To minimize the cost, the king asked you, the bishop, to find the minimal distance between the boundaries of the two islands.

    Input

    The input consists of several test cases.
    Each test case begins with two integers NM. (3 ≤ NM ≤ 10000)
    Each of the next N lines contains a pair of coordinates, which describes the position of a vertex in one convex polygon.
    Each of the next M lines contains a pair of coordinates, which describes the position of a vertex in the other convex polygon.
    A line with N = M = 0 indicates the end of input.
    The coordinates are within the range [-10000, 10000].

    Output

    For each test case output the minimal distance. An error within 0.001 is acceptable.

    Sample Input

    4 4
    0.00000 0.00000
    0.00000 1.00000
    1.00000 1.00000
    1.00000 0.00000
    2.00000 0.00000
    2.00000 1.00000
    3.00000 1.00000
    3.00000 0.00000
    0 0

    Sample Output

    1.00000

    Source

     
    图示:

    思路:找到凸包 p 的 y 值最小点 yminP 和 q 的 y 值最大点ymaxQ,然后分别做切如图。那么AC×AD>AC×AB则说明B还不是离AC最近的点,所以++ymaxQ。

    否则用 AC和 BD 两个线段的距离更新最近距离,并且++yminP,即考察P的下一条边。

    具体实现时,同时旋转体现为逐步选取逆时针方向上的下一个顶点作为C或D、A或B,其实选择卡壳就是只要找到"当前向量面积不小于下一个向量面积"即可,再求两条线段间的最短距离。

    代码:

      1 //#include "bits/stdc++.h"
      2 #include "cstdio"
      3 #include "map"
      4 #include "set"
      5 #include "cmath"
      6 #include "queue"
      7 #include "vector"
      8 #include "string"
      9 #include "cstring"
     10 #include "time.h"
     11 #include "iostream"
     12 #include "stdlib.h"
     13 #include "algorithm"
     14 #define db double
     15 #define ll long long
     16 #define vec vector<ll>
     17 #define mt  vector<vec>
     18 #define ci(x) scanf("%d",&x)
     19 #define cd(x) scanf("%lf",&x)
     20 #define cl(x) scanf("%lld",&x)
     21 #define pi(x) printf("%d
    ",x)
     22 #define pd(x) printf("%f
    ",x)
     23 #define pl(x) printf("%lld
    ",x)
     24 //#define rep(i, x, y) for(int i=x;i<=y;i++)
     25 #define rep(i,n) for(int i=0;i<n;i++)
     26 const int n   = 1e4 + 5;
     27 const int mod = 1e9 + 7;
     28 const int mOD = mod - 1;
     29 const db  eps = 1e-10;
     30 const db  PI  = acos(-1.0);
     31 const int inf=0x3f3f3f3f;
     32 using namespace std;
     33 struct P
     34 {
     35     db x, y;
     36     P() {}
     37     P(db x, db y) : x(x), y(y) {}
     38     P operator + (const P& p){ return P(x + p.x, y + p.y); }
     39     P operator - (const P& p){ return P(x - p.x, y - p.y); }
     40     P operator * (const db& d){ return P(x * d, y * d); }
     41     bool operator < (const P& a) const
     42     {
     43         if (x != a.x) return x < a.x;
     44         else return y < a.y;
     45     }
     46     db dot(const P& p) { return x * p.x + y * p.y; }
     47     db det(const P& p) { return x * p.y - y * p.x; }
     48 };
     49 P p[n], q[n];
     50 // 向量AB 与 AC 的叉积 如果叉积大于0,那么C在向量AB的逆时针方向,叉积小于0则在AB的顺时针方向。如果叉积等于0,则ABC共线。
     51  db cross(P A, P B, P C) {return (B - A).det(C - A); }
     52 // 向量AB 与 AC 的点积 如果点积的结果为0,那么这两个向量互相垂直
     53  db mul(P A, P B, P C)  {return (B - A).dot(C - A); }
     54 // 两点距离
     55  db dis(P A, P B){return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)); }
     56 
     57 // 逆时针排序
     58  void csort(P* p, int n)
     59 {
     60     for (int i = 0; i < n - 2; ++i)
     61     {
     62         db tmp = cross(p[i], p[i + 1], p[i + 2]);
     63         if (tmp > eps) return;
     64         else if (tmp < -eps)
     65         {
     66             reverse(p, p + n);
     67             return;
     68         }
     69     }
     70 }
     71 
     72 //计算C点到线段AB的最短距离
     73  db ptl(P A, P B, P C)
     74 {
     75     if (dis(A, B) < eps) return dis(B, C);
     76     if (mul(A, B, C) < -eps) return dis(A, C);
     77     if (mul(B, A, C) < -eps) return dis(B, C);
     78     return fabs(cross(A, B, C) / dis(A, B));
     79 }
     80 //求一条线段的两端点到另外一条线段的距离,反过来一样,共4种情况
     81  db ltl(P A, P B, P C, P D)
     82 {
     83     return min(min(ptl(A, B, C), ptl(A, B, D)), min(ptl(C, D, A), ptl(C, D, B)));
     84 }
     85 db solve(P* p, P* q, int n, int m)
     86 {
     87     int pmi = 0, qmx = 0;
     88     for (int i = 0; i < n; ++i) if (p[i].y < p[pmi].y) pmi = i;    // P上y坐标最小的顶点
     89     for (int i = 0; i < m; ++i) if (q[i].y > q[qmx].y) qmx = i; // Q上y坐标最大的顶点
     90     p[n] = p[0];    // 为了方便,避免求余
     91     q[m] = q[0];
     92     db tmp, ans = inf;
     93     for (int i = 0; i < n; ++i)
     94     {
     95         while (tmp = cross(p[pmi],p[pmi + 1], q[qmx + 1]) - cross(p[pmi],p[pmi + 1], q[qmx]) > eps) qmx = (qmx + 1) % m;
     96         ans = min(ans, ltl(p[pmi], p[pmi + 1], q[qmx], q[qmx + 1]));
     97         pmi = (pmi + 1) % n;
     98     }
     99     return ans;
    100 }
    101 int main()
    102 {
    103     int n, m;
    104     while (~scanf("%d%d", &n, &m) && n + m)
    105     {
    106         for (int i = 0; i < n; ++i) cd(p[i].x),cd(p[i].y);
    107         for (int i = 0; i < m; ++i) cd(q[i].x),cd(q[i].y);
    108         csort(p, n);
    109         csort(q, m);
    110         printf("%.5lf
    ", solve(p, q, n, m));
    111     }
    112     return 0;
    113 }
  • 相关阅读:
    兼容IE678浏览器的html5标签的几个方案
    CommonJS和AMD/CMD
    axios的使用
    自己写表单校验插件
    表单校验
    JS打开新窗口的2种方式
    mac 上使用移动硬盘
    Boostrap
    Web.config详解
    DataTable
  • 原文地址:https://www.cnblogs.com/mj-liylho/p/8427837.html
Copyright © 2011-2022 走看看