1. 程式人生 > >2017多校六 1002題 hdu 6097 Mindis 相似三角形 計算幾何

2017多校六 1002題 hdu 6097 Mindis 相似三角形 計算幾何

題目連結

題意:

圓心 O 座標(0, 0), 給定兩點 P, Q(不在圓外),滿足 PO = QO,

要在圓上找一點 D,使得 PD + QD 取到最小值。

官方題解:

做P點關於圓的反演點P',OPD與ODP'相似,相似比是|OP| : r。

Q點同理。

極小化PD+QD可以轉化為極小化P'D+Q'D。

當P'Q'與圓有交點時,答案為兩點距離,否則最優值在中垂線上取到。

時間複雜度 O(1)O(1)

補充說明:

反演:

設在平面內給定一點O和常數k(k不等於零),對於平面內任意一點A,確定A′,使A′在直線OA上一點,並且有向線段OA與OA′滿足OA·OA′=k,我們稱這種變換是以O為的

反演中心,以k為反演冪的反演變換,簡稱反演。——百度百科

在這裡,k 即為圓半徑 r ^ 2,因此,相似就是顯然的了。

當 P'Q' 與圓有交點時:

不妨設交點為 O',若 D 不為 O',則 P'D + Q'D >  P'Q'(三角形兩邊之和大於第三邊);當且僅當 D 取 O' 時,P'Q + Q'D 取到最小值,即為 P'Q'。

當 P'Q' 與圓無交點時:

不妨將 P' 與 Q' 看成橢圓的兩個焦點,當橢圓慢慢變大時,第一個碰到的圓上的點 D 即為使得 P'D + Q'D 最小的點;畫個圖就很顯然了,第一個碰到的點即為 PQ 的中垂線與圓的交點。

至於判斷有 P'Q' 與圓有沒有交點,就是圓心到直線的距離與半徑比較,又因為此處 P'O=Q'O,所以只需要比較 P'Q' 的中點到圓心的距離和半徑的大小。

注意點:

1. 注意 PO = QO = 0 的情況

2. 儘量用比例而不是角度進行計算

Code:

#include <bits/stdc++.h>
#define eps 1e-8
void work() {
    double r, x1, y1, x2, y2;
    scanf("%lf%lf%lf%lf%lf", &r, &x1, &y1, &x2, &y2);
    double d0 = sqrt(pow(x1, 2) + pow(y1, 2));
    if (fabs(d0) < eps) {
        printf("%.7f\n", 2 * r);
        return;
    }
    double k = r * r / (d0 * d0);
    double x3 = x1 * k, x4 = x2 * k, y3 = y1 * k, y4 = y2 * k;
    double mx = (x3+x4)/2, my = (y3+y4)/2, ans;
    double d = sqrt(pow(mx,2)+pow(my,2));
    if (d <= r) {
        double dist = sqrt(pow(x3 - x4, 2) + pow(y3 - y4, 2));
        ans = dist * d0 / r;
    }
    else {
        double kk = r / d;
        double smx = mx * kk, smy = my * kk;
        ans = 2 *sqrt(pow(smx - x1, 2) + pow(smy - y1, 2));
    }
    printf("%.7f\n", ans);
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) work();
    return 0;
}


題解裡面還說了...

優秀的黃金分割三分應該也是可以卡過的。

不優秀的三分哭暈在牆角(。

不過看出相似三角形什麼的真是太妙了...服氣