湖南省第十届大学生计算机程序设计竞赛(HNCPC2014)CSG - 1123 : 点到圆弧的距离(计算几何)

Posted quinn18

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了湖南省第十届大学生计算机程序设计竞赛(HNCPC2014)CSG - 1123 : 点到圆弧的距离(计算几何)相关的知识,希望对你有一定的参考价值。

文章目录

题目链接


题意

:输入一个点 P P P 和一条圆弧(圆周的一部分),你的任务是计算 P P P 到圆弧的最短距离。换句话说,你需要在圆弧上找一个点,到 P P P 点的距离最小。

题解

:呃
先找圆心
显然
假如点跟圆心的连线在那段扇形的圆弧范围内,点到圆弧的最短距离为点到圆心的距离减去半径然后取绝对值;不然,点到圆弧的最短的距离为到这段圆弧的两个端点的最小值。

那怎么判断是不是在圆弧范围内呢?

本来想找PB和OA,OC是否有交点但是wa了好像不是精度问题
两个点是不是在一条线的两端可以用叉积判断
判断 C , D C,D C,D 点是否在 A B AB AB线段两边
向量 A B AB AB和向量 A C AC AC是顺时针,所以他们的叉积 > 0 >0 >0
向量 A B AB AB和向量 A D AD AD是逆时针,所以他们的叉积 < 0 <0 <0
只要 C r o s s ( A B , A C ) ∗ C r o s s ( A B , A D ) < 0 Cross(AB,AC)*Cross(AB,AD)<0 Cross(AB,AC)Cross(AB,AD)<0时,就是在不在同一侧
所以这样看, B B B 就在射线 A C AC AC A D AD AD 中间~就可以判断 P P P是否在圆环范围内
对于这题就可以用来判断 P P P是否在 O C , O A OC,OA OC,OA之间

但是上面只适用劣弧的情况 还要考虑平角和优弧的情况 反正还是用这个叉积判qaq

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
const double eps = 1e-8;
const double PI = acos(-1.0);
int sgn(double x) 
    if (fabs(x) < eps) 
        return 0;
    
    return (x < 0) ? -1 : 1;

struct Point 
    double x, y;
    Point(double x = 0.0, double y = 0.0) : x(x), y(y) 
;
typedef Point Vector; //向量
Vector operator + (Vector A, Vector B)  //向量加法
    return Vector(A.x + B.x, A.y + B.y);

Vector operator - (Point A, Point B) 
    return Vector(A.x - B.x, A.y - B.y);

Vector operator * (Vector A, double p) 
    return Vector(A.x * p, A.y * p);

Vector operator / (Vector A, double p) 
    return Vector(A.x / p, A.y / p);

bool operator < (const Point A, const Point B) 
    return A.x < B.x || (sgn(A.x - B.x) == 0 && A.y < B.y);

bool operator == (const Point A, const Point B) 
    return sgn(A.x - B.x) == 0 && sgn(A.y - B.y) == 0;

double Dot(Vector A, Vector B) //点积
    return A.x * B.x + A.y * B.y;

double Cross(Vector A, Vector B) //向量叉积
    return A.x * B.y - A.y * B.x;

double Length(Vector A) //模
    return sqrt(Dot(A, A));

Vector Normal(Vector A) //单位向量
    double L = Length(A);
    return Vector(-A.y / L, A.x / L);

Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) //两直线焦点
    Vector u = P - Q;
    double t = Cross(w, u) / Cross(v, w);
    return P + v * t;

double dis(Point a, Point b) 
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));

signed main() 
    int t=0;
    double x1, y1, x2, y2, x3, y3, xp, yp;
    while(cin >> x1 >>y1 >> x2 >> y2 >> x3 >> y3 >> xp >> yp) 

        Point A =  x1,y1 ;
        Point B =  x2,y2 ;
        Point AB =  (x1 + x2) / 2,(y1 + y2) / 2 ;
        Point C =  x3,y3 ;
        Point BC =  (x3 + x2) / 2,(y3 + y2) / 2 ;
        Point P =  xp,yp ;
        Point O = GetLineIntersection(AB, Normal(A - B), BC, Normal(B - C));//也可以用三角形外心找圆心

		double ans = min(dis(P, A), dis(P, C));
        double d = dis(O, P);
        double r = dis(O, A);
		if((2*r==dis(A, C))) 
			if(Cross(A-C, A-P)*Cross(A-C,A-B)>=0) 
				ans=min(ans, fabs(d-r));
			
			cout << "Case " << ++t << ": " <<fixed<< setprecision(3) << ans << endl;
			continue;
		
        if(Cross(C-A, C-B)*Cross(C-A, C-O)<0) 
			if(Cross(O-A, O-P)*Cross(O-A,O-C)>=0&&Cross(O-C, O-P)*Cross(O-C,O-A)>=0) 
				ans=min(ans, fabs(d-r));
			
        else 
			if(!(Cross(O-A, O-P)*Cross(O-A,O-C)>=0&&Cross(O-C, O-P)*Cross(O-C,O-A)>=0)) 
				ans=min(ans, fabs(d-r));
			
        
        cout << "Case " << ++t << ": " <<fixed<< setprecision(3) << ans << endl;
    
    return 0;



总结

一道计算几何 暖你一整天

以上是关于湖南省第十届大学生计算机程序设计竞赛(HNCPC2014)CSG - 1123 : 点到圆弧的距离(计算几何)的主要内容,如果未能解决你的问题,请参考以下文章

湖南省第十届大学生计算机程序设计竞赛(HNCPC2014)CSG - 1123 : 点到圆弧的距离(计算几何)

湖南省第十二届大学生计算机程序设计竞赛 A 2016

2018年湖南省第十四届大学生计算机程序设计竞赛

湖南省第十二届大学生计算机程序设计竞赛---Parenthesis(线段树求区间最值)

湖南省第十二届大学生计算机程序设计竞赛 problem A 2016

模拟数学CSU 1803 2016 (2016湖南省第十二届大学生计算机程序设计竞赛)