计算几何
Fermat Point in Quadrangle
2010亚洲福州区域赛
题目大意
给出一个平面上的四边形的四点坐标,问你四点坐标到费马点的距离和为多少。
一个多边形的费马点是到这个多边形所有点距离和最小的点
题目输入
一个四边行的四点坐标
x1 y1 x2 y2 x3 y3 x4 y4
若全为-1,则表示结束输入
0 0 1 1 1 0 0 1
1 1 1 1 1 1 1 1
-1 -1 -1 -1 -1 -1 -1 -1
样例输出
距离和
2.8284
0.0000
解题要点
平面四边形中费马点证明相对于三角形中较为简易。
(1)在凸四边形ABCD中,费马点为两对角线AC、BD交点P。
(2)在凹四边形ABCD中,费马点为凹顶点D(P)。
- 当多边形只有1个点时,费马点就是该点,距离和为0
- 当有2个点时,费马点是两点连线的线段上任意一点,距离和为线段长度
- 当有3个点时,若3点共线,则为费马点为中间的那个点,距离和为两端点距离,若3点不共线则为三角形费马点。
- 若三角形3个内角均小于120°,那么3条距离连线正好三等分费马点所在的周角,即该点所对三角形三边的张角相等,均为120°。所以三角形的费马点也称为三角形的等角中心。
若三角形有一内角大于等于120°,则此钝角的顶点就是距离和最小的点。
代码
将四个顶点,以及四个顶点的连成的线的交点(3个)全部当成费马点试一试。
最小值就是答案。
开头用到了ACM国际大学生程序设计竞赛算法与实现中的模板。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double eps=1e-8;
int cmp(double x){
if(fabs(x)<eps)return 0;
if(x>0)return 1;
return -1;
}
struct point{
double x,y;
point(){}
point(double a,double b):x(a),y(b){}
friend point operator -(const point &a,const point &b){
return point(a.x-b.x,a.y-b.y);
}
friend point operator *(const double &a,const point &b){
return point(a*b.x,a*b.y);
}
friend point operator /(const point &a,const double &b){
return point(a.x/b,a.y/b);
}
double norm(){
return sqrt(x*x+y*y);
}
};
double det(const point&a,const point&b){
return a.x*b.y-a.y*b.x;
}
double dist(const point &a,const point &b){
return (a-b).norm();
}
//---------------------------------
struct line{
point a,b;
line(){}
line(point x,point y):a(x),b(y){}
};
bool parallel(line a,line b){
return !cmp(det(a.a-a.b,b.a-b.b));
}
bool line_make_point(line a,line b,point &res){
if(parallel(a,b))return false;
double s1=det(a.a-b.a,b.b-b.a);
double s2=det(a.b-b.a,b.b-b.a);
res=(s1*a.b-s2*a.a)/(s1-s2);
return true;
}
point p[4];
double sumdist(point x){
return dist(x,p[0])+dist(x,p[1])+dist(x,p[2])+dist(x,p[3]);
}
int main(){
while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&p[0].x,&p[0].y,&p[1].x,&p[1].y,&p[2].x,&p[2].y,&p[3].x,&p[3].y)){
if(p[0].x==-1&&p[0].y==-1&&p[1].x==-1&&p[1].y==-1&&p[2].x==-1&&p[2].y==-1&&p[3].x==-1&&p[3].y==-1)
break;
double ans=99999999;
for(int i=0;i<4;i++)
ans=min(ans,sumdist(p[i]));
point temp;
if(line_make_point(line(p[0],p[1]),line(p[2],p[3]),temp)){
ans=min(ans,sumdist(temp));
}
if(line_make_point(line(p[0],p[2]),line(p[1],p[3]),temp)){
ans=min(ans,sumdist(temp));
}
if(line_make_point(line(p[0],p[3]),line(p[1],p[2]),temp)){
ans=min(ans,sumdist(temp));
}
printf("%.4lf\n",ans);
}
return 0;
}