CSU 1503: 点到圆弧的距离(计算几何)

Posted 抓不住Jerry的Tom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSU 1503: 点到圆弧的距离(计算几何)相关的知识,希望对你有一定的参考价值。

题目描述

输入一个点 P 和一条圆弧(圆周的一部分),你的任务是计算 P 到圆弧的最短距离。换句话 说,你需要在圆弧上找一个点,到 P点的距离最小。 
提示:请尽量使用精确算法。相比之下,近似算法更难通过本题的数据。 

输入

输入包含最多 10000组数据。每组数据包含 8个整数 x1, y1, x2, y2, x3, y3, xp, yp。圆弧的起点 是 A(x1,y1),经过点 B(x2,y2),结束位置是 C(x3,y3)。点 P的位置是 (xp,yp)。输入保证 A, B, C 各不相同且不会共线。上述所有点的坐标绝对值不超过 20。

输出

对于每组数据,输出测试点编号和 P 到圆弧的距离,保留三位小数。

样例输入

0 0 1 1 2 0 1 -1
3 4 0 5 -3 4 0 1 

样例输出

Case 1: 1.414
Case 2: 4.000


分两种情况:

第一种:点跟圆心的连线在那段扇形的圆弧范围内,点到圆弧的最短距离为点到圆心的距离减去半径然后取绝对值;

第二种:点跟圆心的连线不在那段扇形的圆弧范围内,点到圆弧的最短的距离为到这段圆弧的两个端点的最小值。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const double eps  = 1e-8;
 4 const double PI = acos(-1.0);
 5 int casee = 0;
 6 int dcmp(double x) {
 7     if(fabs(x) < eps) return 0;
 8     else return x < 0 ? -1 : 1;
 9 }
10 struct Vector {
11     double x, y;
12     Vector(double x_ = 0, double y_ = 0) : x(x_), y(y_) {}
13 
14     Vector operator+ (const Vector &a) const {
15         return Vector(x + a.x, y + a.y);
16     }
17     Vector operator- (const Vector &a) const {
18         return Vector(x - a.x, y - a.y);
19     }
20     Vector operator* (double p) {
21         return Vector(x * p, y * p);
22     }
23     friend Vector operator* (double p, const Vector &a) {
24         return Vector(a.x * p, a.y * p);
25     }
26     Vector operator/ (double p) {
27         return Vector(x / p, y / p);
28     }
29     bool operator== (const Vector &a) const {
30         return dcmp(x - a.x) == 0 && dcmp(y - a.y) == 0;
31     }
32 
33     friend double dmul(const Vector &a, const Vector &b) {
34         return a.x * b.x + a.y * b.y;
35     }
36     friend double cmul(const Vector &a, const Vector &b) {
37         return a.x * b.y - a.y * b.x;
38     }
39     friend double angle(const Vector &a, const Vector &b) {
40         return acos(dmul(a, b) / a.length() / b.length());
41     }
42     friend Vector rotate(const Vector &a, double rad) {
43         return Vector(a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad));
44     }
45     friend Vector normal(const Vector &a) {
46         double l = a.length();
47         return Vector(a.x / l, a.y / l);
48     }
49 
50     double length() const {
51         return sqrt(dmul(*this, *this));
52     }
53 };
54 typedef Vector Point;
55 double dis(Point A, Point B) {
56     return (A-B).length();
57 }
58 Point pp1, pp2, pp3, pp, o;
59 
60 Point get_cir(Point a,Point b,Point c) {//已知圆上3点,求圆的外心
61     double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;
62     double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;
63     double d=a1*b2-a2*b1;
64     return Point(a.x+(c1*b2-c2*b1)/d,a.y+(a1*c2-a2*c1)/d);
65 }
66 double AngleToX(Vector A, Vector B) {//向量与x轴正方向的夹角,范围[0,2*pi) B为(1,0)
67     double res = angle(A, B);
68     if(dcmp(cmul(A, B)) < 0) res = PI * 2 - res;
69     return res;
70 }
71 void gao (Point A,Point B,Point C,Point P,Point O)
72 {
73     Vector X(1, 0);
74     Vector OA = A - O, OP = P - O, OC = C - O, OB = B - O;
75     double fa = AngleToX(OA, X);
76     double fb = AngleToX(OB, X);
77     double fc = AngleToX(OC, X);
78     double fp = AngleToX(OP, X);
79     double ans = min(dis(P, A), dis(P, C));
80     double r = dis(A, O);
81     if(fa>fc) swap(fa,fc);
82     if(dcmp(fa-fb)<=0 && dcmp(fb - fc) <= 0 && dcmp(fa - fp) <= 0 && dcmp(fp - fc) <= 0) {
83         double r = dis(A, O);
84         ans = min(ans, fabs(dis(O, P) - r));
85     }
86     if(!(dcmp(fa - fb) <= 0 &&dcmp(fb-fc)<= 0)&&!(dcmp(fa-fp)<=0&&dcmp(fp-fc)<=0)) {
87         ans = min(ans, fabs(dis(O, P)- r));
88     }
89 
90     printf("Case %d: %.3f\n", ++casee, ans);
91 }
92 int main() {
93     while(~scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &pp1.x,&pp1.y,&pp2.x,&pp2.y,&pp3.x,&pp3.y,&pp.x,&pp.y)){
94         o=get_cir(pp1,pp2,pp3);
95         gao(pp1,pp2,pp3,pp,o);
96     }
97     return 0;
98 }

解法2

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 #include <map>
 6 #define eps (1e-4)
 7 #define N 205
 8 #define dd double
 9 #define sqr(x) ((x)*(x))
10 const double pi = acos(-1);
11 using namespace std;
12 struct Point
13 {
14     double x,y;
15 };
16 double cross(Point a,Point b,Point c) ///叉积
17 {
18     return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
19 }
20 double dis(Point a,Point b) ///距离
21 {
22     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
23 }
24 Point waixin(Point a,Point b,Point c) ///外接圆圆心坐标
25 {
26     Point p;
27     double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1)/2;
28     double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2)/2;
29     double d = a1*b2 - a2*b1;
30     p.x = a.x + (c1*b2 - c2*b1)/d, p.y=a.y + (a1*c2 -a2*c1)/d;
31     return p;
32 }
33 bool judge(Point a,Point b,Point c,Point p){ ///此模板判断点 p 是否在两条射线 ab 和 ac 之间(但是p点不在 ab或者 ac上)
34     if(cross(b,c,a)>0&&cross(p,a,c)<0&&cross(p,a,b)>0){ ///b 在 c 的逆时针方向
35         return true;
36     }
37     if(cross(b,c,a)<0&&cross(p,a,c)>0&&cross(p,a,b)<0){ ///b 在 c 的顺时针方向
38         return true;
39     }
40     return false;
41 }
42 bool judge1(Point a,Point b,Point c,Point p){ ///此模板判断点 p 是否在两条射线 ab 和 ac 之间(p点可以在 ab或者 ac上)
43     if(cross(b,c,a)>0&&cross(p,a,c)<=0&&cross(p,a,b)>=0){ ///b 在 c 的逆时针方向
44         return true;
45     }
46     if(cross(b,c,a)<0&&cross(p,a,c)>=0&&cross(p,a,b)<=0){ ///b 在 c 的顺时针方向
47         return true;
48     }
49     return false;
50 }
51 int main()
52 {
53     Point a,b,c,p;
54     int t = 1;
55     freopen("a.in","r",stdin);
56     freopen("a.txt","w",stdout);
57     while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y,&c.x,&c.y,&p.x,&p.y)!=EOF)
58     {
59 
60         Point circle = waixin(a,b,c);
61         double r = dis(circle,a);
62         double ans = min(dis(p,a),dis(p,c));
63         double op = dis(circle,p);
64         if(fabs(2*r-dis(a,c))<eps){ ///平角特殊处理
65             if(cross(p,c,circle)*cross(b,c,circle)>=0){
66                 ans = min(ans,fabs(op-r));
67             }
68             printf("Case %d: %.3lf\n",t++,ans);
69             continue;
70         }
71         if(judge(circle,a,c,b))  ///劣弧
72         {
73             if(judge1(circle,a,c,p)) ans = min(ans,fabs(op-r));
74         }
75         else
76         {
77             if(!judge(circle,a,c,p)) ans = min(ans,fabs(op-r));
78         }
79         printf("Case %d: %.3lf\n",t++,ans);
80     }
81 }

标程:

 1 // Rujia Liu
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<iostream>
 5 
 6 using namespace std;
 7 
 8 const double PI = acos(-1.0);
 9 const double TWO_PI = 2 * PI;
10 const double eps = 1e-6;
11 
12 inline double NormalizeAngle(double rad, double center = PI) {
13   return rad - TWO_PI * floor((rad + PI - center) / TWO_PI);
14 }
15 
16 inline int dcmp(double x) {
17   if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;
18 }
19 
20 struct Point {
21   double x, y;
22   Point(double x=0, double y=0):x(x),y(y) { }
23 };
24 
25 typedef Point Vector;
26 
27 inline Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }
28 inline Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y); }
29 
30 inline double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }
31 inline double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }
32 inline double Length(Vector A) { return sqrt(Dot(A, A)); }
33 
34 // 外接圆圆心。假定三点不共线
35 Point get_circumscribed_center(Point p1, Point p2, Point p3) {
36   double bx = p2.x - p1.x;
37   double by = p2.y - p1.y;
38   double cx = p3.x - p1.x;
39   double cy = p3.y - p1.y;
40   double d = 2 * (bx * cy - by * cx);
41   Point p;
42   p.x = (cy * (bx * bx + by * by) - by * (cx * cx + cy * cy)) / d + p1.x;
43   p.y = (bx * (cx * cx + cy * cy) - cx * (bx * bx + by * by)) / d + p1.y;
44   return p;
45 }
46 
47 double DistanceToArc(Point a, Point start, Point mid, Point end) {   ///点到圆弧的距离
48   Point p = get_circumscribed_center(start, mid, end);
49   bool CCW = dcmp(Cross(mid - start, end - start)) > 0;
50   double ang_start = atan2(start.y-p.y, start.x-p.x);
51   double ang_end = atan2(end.y-p.y, end.x-p.x);
52   double r = Length(p - start);
53   double ang = atan2(a.y-p.y, a.x-p.x);
54   bool inside;
55   if(CCW) {
56     inside = NormalizeAngle(ang - ang_start) < NormalizeAngle(ang_end - ang_start);
57   } else {
58     inside = NormalizeAngle(ang - ang_end) < NormalizeAngle(ang_start - ang_end);
59   }
60   if(inside) {
61     return fabs(r - Length(p - a));
62   }
63   return min(Length(a - start), Length(a - end));
64 }
65 
66 int main() {
67   int kase = 0;
68   double x1, y1, x2, y2, x3, y3, xp, yp;
69   while(cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> xp >> yp) {
70     double ans = DistanceToArc(Point(xp,yp), Point(x1,y1), Point(x2,y2), Point(x3,y3));
71     printf("Case %d: %.3lf\n", ++kase, ans);
72   }
73   return 0;
74 }

 

以上是关于CSU 1503: 点到圆弧的距离(计算几何)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

点到多边形最近边的距离

点到平面距离公式是啥?

[COCI2009]Dvapravca 计算几何

什么是曲面及曲面在画法几何中起到什么作用?