2018codeM美團初賽B輪 4.神奇盤子

[編程|1500分] 神奇盤子

時間限制:C/C++ 1秒,其他語言 2秒
空間限制:C/C++ 262144K,其他語言 524288K
Special Judge,64bit IO Format: %lld

題目描述

有一個神奇的盤子,形狀爲圓形。盤子上面爬着一個大象(視作一個點)。由於現實的扭曲,當大象在盤子某個直徑的一端的時候,可以瞬間傳送至直徑的另一端。現在大象想去盤子上另外一點,問他最少需要移動多少距離。傳送不計距離。

輸入描述:

第一行一個整數r(1 <= r <= 1000)代表盤子的大小。
第二行兩個整點分別代表大象所在的位置和大象目標的位置。保證兩個點都在圓內(可能在邊界上),圓心在點(0, 0)上。

輸出描述:

輸出一個實數,代表大象最短需要移動多少距離。和標程相對或絕對相差1e-6都算正確。

示例1

輸入
1
0 1
0 -1
輸出
0.000000000000

示例2

輸入
4
3 0
-3 0
輸出
2.000000000000
說明
這裏寫圖片描述

示例3

輸入
100
-59 76
3 69
輸出
62.393909959226

代碼 (之前的代碼只跑了77.42%,更新了代碼)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=1e6+10;
double esp=1e-6;
double r,x11,y11,x22,y22;
double pi=acos(-1.0);
double dist(double x1,double y1,double x2,double y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{

    while(cin>>r>>x11>>y11>>x22>>y22)
    {
        double ans=dist(x11,y11,x22,y22);
        double x,y;
        for(double i=0;i<=pi;i+=0.000001)
        {
            x=r*cos(i),y=r*sin(i);
            //cout<<x<<" "<<y<<endl;
            ans=min(ans,dist(-x,-y,x11,y11)+dist(x,y,x22,y22));
            ans=min(ans,dist(x,y,x11,y11)+dist(-x,-y,x22,y22));
        }

        printf("%.15f\n",ans);

    }


    return 0;
}

另附官方題解

思路

把一個點(x,y)翻到(-x,-y),就可以把題意轉換爲在圓周上求一個點,使得這個點到起點
與終點的距離和最小。直接三分角度或二分導數就可以了。時間複雜度爲O(nm)。

#include<bits/stdc++.h>
using namespace std;
typedef long double D;
D pi = acos(-1.);
D eps = 1e-8;
inline int sign(const D & x) {
    return (x > eps) - (x + eps < 0);
}
struct P {
    D x, y;
    void scan() {
        double _x, _y;
        scanf("%lf%lf", &_x, &_y);
        x = _x; y = _y;
    }
    D sqrlen() const {
        return x * x + y * y;
    }
    D len() const {
        return sqrt(max((D)0., sqrlen()));
    }
    P operator + (const P & b) const {
        return P{x + b.x, y + b.y};
    }
    P operator - (const P & b) const {
        return P{x - b.x, y - b.y};
    }
    D operator % (const P & b) const {
        return x * b.x + y * b.y;
    }
    D operator * (const P & b) const {
        return x * b.y - y * b.x;
    }
    P zoom(const D & l) const {
        D lambda(l / len());
        return P{lambda * x, lambda * y};
    }
    void print() const {
        printf("%.12f %.12f\n", (double)x, (double)y);
    }
};
D atan2(const P & x) { return atan2(x.y, x.x); }
P operator * (const D & x, const P & a) { return P{x * a.x, x * a.y}; }
int main() {
    int r;
    scanf("%d", &r);
    P a, b;
    a.scan(); b.scan();
    D ans((a - b).len());
    b = -1. * b;
    if(sign(a * b) == 0) {
        ans = min(ans, 2 * r - ans);
    }else {
        D t1 = atan2(a), t2 = atan2(b);
        if(t1 > t2) swap(t1, t2), swap(a, b);
        if(t2 - t1 > pi) t1 += pi, swap(t1, t2), swap(a, b);
        D le = t1, ri = t2;
        for(int i(0); i < 1000; i++) {
            D mid((le + ri) / 2);
            P p = r * P{cos(mid), sin(mid)};
            //p.print();
            if(((p - a).zoom(1) - (p - b).zoom(1)) % (p - P{0, 0}) > 0) {
                le = mid;
            }else ri = mid;
        }
        P p = r * P{cos(le), sin(le)};
        ans = min(ans, (p - a).len() + (p - b).len());
    }
    printf("%.12f\n", (double)ans);

}
發佈了46 篇原創文章 · 獲贊 58 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章