【题解】Railway [Uva10263]
传送门:\(\text{Railway [Uva10263]}\)
【题目描述】
给出点 \(M\) 以及一个由 \(n\) 条线段依次相连的类曲形图(由 \(n+1\) 个点构成),求该“曲形”图中距离点 \(M\) 最近的点 \(P\) 的坐标(\(P\) 可以在任意一条线段上)。
【输入】
输入多组数据,读至 \(EOF\) 结束。
每组数据第一、二行为点 \(M\) 的坐标,接下来一个整数 \(n\) 以及 \(2(n+1)\) 行表示 \(n+1\) 的点的坐标。
【输出】
对于每组数据,输出两行分别表示点 \(P\) 的横、纵坐标。
【样例】
样例输入:
6
-3
3
0
1
5
5
9
-5
15
3
0
0
1
1
0
2
0
样例输出:
7.8966
-2.2414
1.0000
0.0000
【分析】
【计算几何全家桶】
计算几何基础题。
在输入时记录上一个点的坐标,分别求点 \(M\) 与 \(n\) 条线段的最短距离即可。
\((1).\) 求点 \(P\) 到线段 \(AB\) 最短距离:
先判断垂足 \(F\) 的位置,如果在 \(AB\) 的延长线上,则最短距离为 \(PB\),如果在 \(BA\) 的延长线上,则最短距离为 \(PA\),否则为 \(PF\)。
\((2).\) 求点 \(P\) 到线段 \(AB\) 的垂足 \(F\):
分别计算 \(AP,BP\) 在 \(AB,BA\) 上的投影并作比,得到 \(AF\) 与 \(AB\) 的比,而 \(AB\) 已知,则可得点 \(AF\),最后再算出 \(F\)。
【Code】
#include
#include
#include
#define LD double
#define LL long long
#define Vector Point
#define Re register int
using namespace std;
const int N=1e5+3;
const LD eps=1e-8;
int n;
inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}
inline LD Abs(LD a){return a*dcmp(a);}
struct Point{
LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
inline void in(){scanf("%lf%lf",&x,&y);}
}M,P1,P2;
inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
inline LD Len(Vector a){return sqrt(Dot(a,a));}
inline LD Angle(Vector a,Vector b){return acos(Dot(a,b)/Len(a)/Len(b));}
inline Point operator+(Point a,Vector b){return Point(a.x+b.x,a.y+b.y);}
inline Vector operator-(Point a,Point b){return Vector(a.x-b.x,a.y-b.y);}
inline Vector operator*(Vector a,LD x){return Vector(a.x*x,a.y*x);}
inline bool operator==(Point a,Point b){return !dcmp(a.x-b.x)&&!dcmp(a.y-b.y);}
struct ANS{Point a;LD dis;ANS(Point A,LD D=0){a=A,dis=D;}};
inline Point FootPoint(Point p,Point a,Point b){//点P到直线AB的垂足
Vector x=p-a,y=p-b,z=b-a;
LD len1=Dot(x,z)/Len(z),len2=-1.0*Dot(y,z)/Len(z);//分别计算AP,BP在AB,BA上的投影
return a+z*(len1/(len1+len2));//点A加上向量AF
}
inline Point dis_PL(Point p,Point a,Point b){//点P到线段AB距离
if(a==b)return a;//AB重合
Vector x=p-a,y=p-b,z=b-a;
if(dcmp(Dot(x,z))<0)return a;//P距离A更近
if(dcmp(Dot(y,z))>0)return b;//P距离B更近
return FootPoint(p,a,b);//返回垂足
}
int main(){
// freopen("123.txt","r",stdin);
while(~scanf("%lf%lf",&M.x,&M.y)){
scanf("%d",&n),P1.in();
Point ans=P1;
while(n--){
P2.in();Point tmp=dis_PL(M,P1,P2);
if(dcmp(Len(M-tmp)-Len(M-ans))<0)ans=tmp;
P1=P2;
}
printf("%.4lf\n%.4lf\n",ans.x,ans.y);
}
}