1. 程式人生 > >Bridge Across Islands POJ - 3608 旋轉卡殼求凸包最近距離

Bridge Across Islands POJ - 3608 旋轉卡殼求凸包最近距離

\(\color{#0066ff}{題目描述}\)

幾千年前,有一個小王國位於太平洋的中部。王國的領土由兩個分離的島嶼組成。由於洋流的衝擊,兩個島嶼的形狀都變成了凸多邊形。王國的國王想建立一座橋來連線這兩個島嶼。為了把成本降到最低,國王要求你,主教,找到兩個島嶼邊界之間最小的距離。

\(\color{#0066ff}{輸入格式}\)

輸入由幾個測試用例組成。
每個測試用兩個整數n,m(3≤n,m≤10000)開始
接下來的n行中的每一行都包含一對座標,用來描述頂點在一個凸多邊形中的位置。
下一條m線中的每一條都包含一對座標,它描述了一個頂點在另一個凸多邊形中的位置。
n=m=0的行表示輸入的結束。
座標在這個範圍內[-10000,10000]。

\(\color{#0066ff}{輸出格式}\)

對每個測試用例輸出最小距離。在0.001範圍內的錯誤是可以接受的

\(\color{#0066ff}{輸入樣例}\)

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

\(\color{#0066ff}{輸出樣例}\)

1.00000

\(\color{#0066ff}{資料範圍與提示}\)

none

\(\color{#0066ff}{題解}\)

旋轉卡殼

輸入的時候就是凸包,所以不用再求了

對於最近距離,可能是點點,點邊, 邊邊,這個可以在點到邊的距離那裡一併處理

距離可以通過面積判斷(底固定,高最大)

(叉積是負的,所以用<) 找到高最小的更新ans

#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#define _ 0
#define LL long long
inline LL in() {
    LL x = 0, f = 1; char ch;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
    return x * f;
}
const int maxn = 1e4 + 100;
int n, m;
struct node {
    double x, y;
    node(double x = 0, double y = 0)
        :x(x), y(y) {}
    node operator - (const node &b) const {
        return node(x - b.x, y - b.y);
    }
    double operator ^ (const node &b) const {
        return x * b.y - y * b.x;
    }
    double operator * (const node &b) const {
        return x * b.x + y * b.y;
    }
    double dis() {
        return sqrt(x * x + y * y);
    }
    double dis(const node &a, const node &b) {
        node c = *this;
        //垂足不線上段ab上
        if((b - a) * (c - a) < 0) return (c - a).dis();
        if((a - b) * (c - b) < 0) return (c - b).dis();
        //平行四邊形面積 / 底 = 高
        return fabs(((a - b) ^ (c - b)) / (a - b).dis());
    }
}A[maxn], B[maxn];
double Min(node a, node b, node c, node d) { 
    return std::min(std::min(c.dis(a,b),d.dis(a,b)),std::min(a.dis(c,d),b.dis(c,d)));
}
double work() {
    double ans = 1e20;
    int min = 0, max = 0;
    for(int i = 0; i < n; i++) if(A[i].y < A[min].y) min = i;
    for(int i = 0; i < m; i++) if(B[i].y > B[max].y) max = i;
    A[n] = A[0], B[m] = B[0];
    for(int i = 0; i < n; i++) {
        node t = A[min + 1] - A[min];
        while((t ^ (B[max] - A[min]))  < (t ^ (B[max + 1] - A[min]))) max = (max + 1) % m;
        ans = std::min(ans, Min(A[min], A[min + 1], B[max], B[max + 1]));
        min = (min + 1) % n;
    }
    return ans;
}
int main() {
    while("fuck") {
        n = in(), m = in();
        if(!n && !m) break; 
        for(int i = 0; i < n; i++) scanf("%lf%lf", &A[i].x, &A[i].y);
        for(int i = 0; i < m; i++) scanf("%lf%lf", &B[i].x, &B[i].y);
        printf("%.3f\n", work());
    }
    return 0;
}