題目鏈接:CSU 1503 點到圓弧的距離
中文題。
思路:求一個二元函數在圓弧上的極值,加上端點的值,一起取個最小就是答案。
注意:1+λ爲0時,P點在圓心,最短距離自然是半徑。
求的極值點在圓的優弧或是劣弧的判斷可以將直角座標系轉爲極座標,用角度判斷。
還有就是最坑的精度,精度要達到0.0001
AC代碼;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const double eps=0.0001;
const double PI=acos(-1.0);
struct Point
{
double x,y;
};
Point waixion(Point a,Point b,Point c)
{
Point e;
double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1)/2;
double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2)/2;
double d = a1*b2 - a2*b1;
e.x=a.x + (c1*b2 - c2*b1)/d;
e.y=a.y + (a1*c2 -a2*c1)/d;
return e;
}
double dis(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double cross(Point a,Point b)
{
return b.x*a.y-a.x*b.y;
}
double angle(Point a,Point c,double r)
{
double aa,d;
d=dis(a,c);
aa=acos((a.x-c.x)/d);
if((sin(aa)*d-(a.y-c.y))<=eps)
return aa;
return 2*PI-aa;
}
int main()
{
double h;
int cas = 0;
double ans1,r,x,y;
Point yx,a,b,c,p,ans;
while(scanf("%lf%lf%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y,&c.x,&c.y)!=EOF)
{
scanf("%lf%lf",&p.x,&p.y);
yx=waixion(a,b,c);
r=dis(yx,a);
h=sqrt(((p.x-yx.x)*(p.x-yx.x)+(p.y-yx.y)*(p.y-yx.y))/(r*r))-1;
if(fabs(p.x-yx.x)<=eps && fabs(p.y-yx.y)<=eps)
{
printf("Case %d: %.3lf\n",++cas,r);
continue;
}
ans.x=(h*yx.x+p.x)/(1+h);
ans.y=(h*yx.y+p.y)/(1+h);
double ja,jb,jc,jp;
ja=angle(a,yx,r);
jb=angle(b,yx,r);
jc=angle(c,yx,r);
jp=angle(p,yx,r);
//printf("a:%lf\nb:%lf\nc:%lf\np:%lf\n",ja,jb,jc,jp);
if(ja>jc)
swap(ja,jc);
if(ja-jb<=eps && jb-jc<=eps)//ja<jb<jc
{
if(ja-jp<=eps && jp-jc<=eps)
ans1= dis(ans,p);
else
ans1=9999999999.0;
}
else
{
if(ja-jp<=eps && jp-jc<=eps)
ans1=9999999999.0;
else
ans1= dis(ans,p);
}
double ans2 = dis(a,p);
double ans3 = dis(c,p);
double ans = min(ans1,ans2);
ans = min(ans,ans3);
//printf("%.2lf %.2lf %.2lf....\n",ans1,ans2,ans3);
printf("Case %d: %.3lf\n",++cas,ans);
}
return 0;
}
/*
0 0 1 -1 2 0 1 -1
0 0 1 1 2 0 0 1
3 4 0 -5 -3 4 0 1
3 4 0 5 -3 4 0 1
1 0 -1 0 0 -1 1 -1
*/