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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章