湖南省第十届大学生计算机程序设计竞赛(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 : 点到圆弧的距离(计算几何)
湖南省第十二届大学生计算机程序设计竞赛---Parenthesis(线段树求区间最值)