2020.01.19【NOIP提高组】模拟B 组——总结——水池

探讨了在圆形水池中,如何计算两点间最短路径的问题,利用三角函数和几何原理,给出了具体的算法实现。

Description

有一个圆形的水池,水池的圆心坐标为(0, 0)。有座桥跨越水池,桥可以看作直线段AB,A点和B点都在水池边上。
Merlin想从F点走到G点,并且F点和G点都在水池边上,但是他不会游泳。请告诉他从F点到G点的最短路程是多少。

Input

输入有多组数据。
每组数据的第一行是一个整数R (1<=R<=100), 表示水池的半径。
第二行包含8个实数XA, YA, XB, YB, XF, YF, XG, YG, 分别表示A,B,F,G点的坐标。每组坐标满足|X2+Y2-R2| < 10-8。

Output

每组数据输出一行,输出答案四舍五入到两位小数。

Sample Input

1
0.729627 -0.683845334 0.198022 -0.9801975758 0.314911 -0.9491212052 -0.735596 -0.6774204933
1
0.517308 0.8557992949 0.936038 -0.351898938 0.396901 -0.9178614254 0.616543 -0.7873212363

Sample Output

1.15
0.26

Data Constraint

数据范围
对于所有数据,1<=R<=100,|X2+Y2-R2| < 10-8。

赛时

旁边一位大佬说是三角函数,然后他就a了,于是我也无视这道题。

正解

上网查三角函数找公式,(还看了看别人的博客):

别人的:

两点间的弦长(设为d):d=根号下[(x2-x1)²+(y2-y1)²]
圆心角θ=2arcsin(d/2r)
弧长L=rθ=2r·arcsin(d/2r
AB距离为sqrt((XA-XB)(XA-XB)+(YA-YB)(YA-YB));

代码

#include<bits/stdc++.h>
#define PI 3.1415926
using namespace std;
int r;
double xa,ya,xb,yb,xf,yf,xg,yg,fg,ab,abfg;
double min(double a, double b){return a<b?a:b;}
double hu(double x1,double y1,double x2,double y2,double r){
    double xc,yxj1,yxj2,h1,h2;
    xc=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    yxj1=asin(xc/(2*r))*2,yxj2=PI*2-yxj1;
    h1=r*yxj1,h2=r*yxj2;
    return min(h1,h2);
}
int main(){
	freopen("pool.in","r",stdin);
	freopen("pool.out","w",stdout);
    while(scanf("%d",&r)!=EOF){
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&xa,&ya,&xb,&yb,&xf,&yf,&xg,&yg);
        fg=hu(xf,yf,xg,yg,r);
        ab=sqrt((xa-xb)*(xa-xb)+(ya-yb)*(ya-yb));
        abfg=min(hu(xa,ya,xf,yf,r),hu(xb,yb,xf,yf,r))+min(hu(xb,yb,xg,yg,r),hu(xa,ya,xg,yg,r));
        printf("%.2lf\n",min(fg,ab+abfg));
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值