1. 程式人生 > >CSU 1503 點到圓弧的距離(最易理解)

CSU 1503 點到圓弧的距離(最易理解)

第一步找出圓心

根據題目給出的三點建立兩條直線,兩直線垂直平分線的交點就是圓心

第二步判斷點與圓弧的位置關係

通過分析,可分為兩種情況;

情況一,ans1為p到p1的距離減去圓的半徑的絕對值

情況二,ans2為p到A,C兩點的距離最小值

給出f1,f2,f3,f4分別表示向量 p1A, p1B,p1C,p1P與x正半軸的夾角;

考慮到沒有給出給點的順序,有可能順時針或逆時針給點。

給出判斷的程式碼:

if(f1<f3){
	if((f2<=f3&&f2>=f1) == (f4<=f3&&f4>=f1))ans=ans1;
	else ans=ans2;
}else{
	if((f2>=f3&&f2<=f1) == (f4>=f3&&f4<=f1))ans=ans1;
	else ans=ans2;
}

下面分析這段程式碼:

f1<f3時,表示A,C的位置關係

順時針給點會形成如下的圓弧;

顯然f2 不會滿足 f2<=f3&&f2>=f1 如果 f4也不滿足 f4<=f3&&f4>=f1,即(f2<=f3&&f2>=f1) == (f4<=f3&&f4>=f1)

則答案是ans1;

如果f4滿足 f4<=f3&&f4>=f1 即(f2<=f3&&f2>=f1) != (f4<=f3&&f4>=f1)

則答案是ans2;

逆時針給點會形成如下的圓弧;

顯然f2 滿足 f2<=f3&&f2>=f1如果 f4也滿足 f4<=f3&&f4>=f1,即(f2<=f3&&f2>=f1) == (f4<=f3&&f4>=f1)

則答案是ans1;

如果f4不滿足 f4<=f3&&f4>=f1 即(f2<=f3&&f2>=f1) != (f4<=f3&&f4>=f1)

則答案是ans2;

f1>=f3時的情況按照上面的步驟分析一下即可

完整程式碼:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath> 
using namespace std;
struct Point{
	double x,y;
	Point(double x=0,double y=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 - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double B){return Vector(A.x*B,A.y*B);}
Vector operator / (Vector A,double B){return Vector(A.x/B,A.y/B);}

double Dot(Vector A,Vector B){return A.x*B.x+A.y*B.y;}
double Length(Vector A){return sqrt(Dot(A,A));}
double Cross(Vector A,Vector B){return A.x*B.y-B.x*A.y;}

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 Distance(Point a,Point b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main(){
	Point a,b,c,p,p1;
	int Case=0;
	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)){
		Point mid1,mid2;
		mid1.x=(a.x+b.x)/2;mid1.y=(a.y+b.y)/2;
		mid2.x=(a.x+c.x)/2;mid2.y=(a.y+c.y)/2;
		Vector v1=(b-a);
		Vector v2=(c-a);
		v1=Normal(v1);
		v2=Normal(v2);
		p1=GetLineIntersection(mid1,v1,mid2,v2);//通過三點建立兩直線,兩直線的垂直平分線交點就是圓心
		
		double ans,ans1,ans2;
		double da,dc,dp1,r;
		dp1=Distance(p,p1);
		r=Distance(p1,a);
		da=Distance(p,a);
		dc=Distance(p,c);
		
		ans1=fabs(dp1-r); 
		ans2=min(da,dc);

		double f1=atan2(a.y-p1.y,a.x-p1.x);
		double f2=atan2(b.y-p1.y,b.x-p1.x);
		double f3=atan2(c.y-p1.y,c.x-p1.x);
		double f4=atan2(p.y-p1.y,p.x-p1.x);
		if(f1<f3){
			if((f2<=f3&&f2>=f1) == (f4<=f3&&f4>=f1))ans=ans1;
			else ans=ans2;
		}else{
			if((f2>=f3&&f2<=f1) == (f4>=f3&&f4<=f1))ans=ans1;
			else ans=ans2;
		}
		printf("Case %d: %.3lf\n",++Case,ans);
	}
	return 0;
}