求四边形的费马点

费马点的定义:在平面上的到四边形四个顶点A,B,C,D的点


当ABCD为凸四边形的时候

可以证明M点是费马点,M是对角线的交点

当ABCD为凹四边形的时候

在ABCD四点中有某一个点为费马点


所以,这个点就是个计算几何的模板题啦~~~~~~

我们也不需要判断四边形的凹凸性

把六条线段算出来,判断是不是有交点就好,然后暴力枚举每一个可能性


#include<bits/stdc++.h>
using namespace std;

const double eps=1e-6;
const double inf=1e20;
const double pi=acos(-1.0);
const int maxp=1010;

int sgn(double x){
    if (fabs(x)<eps) return 0;
    if (x<0) return -1;
    else return 1;
}

double sqr(double x){
    return x*x;
}

struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){
        x=_x;
        y=_y;
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    void output(){
        printf("%.2lf %.2lf\n",x,y);
    }
    double operator ^ (const Point &b) const{
        return x*b.y-y*b.x;
    }
    double operator * (const Point &b) const{
        return x*b.x+y*b.y;
    }
    double len2(){
        return x*x+y*y;
    }
    double len(){
        return sqrt(x*x+y*y);
    }
    double distance(Point p){
        return hypot(x-p.x,y-p.y);
    }
    Point operator - (const Point &b) const{
        return Point(x-b.x,y-b.y);
    }
    Point operator + (const Point &b) const{
        return Point(x+b.x,y+b.y);
    }
    Point operator * (const double &k) const{
        return Point(x*k,y*k);
    }
    Point operator / (const double &k) const{
        return Point(x/k,y/k);
    }
};

struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e){
        s=_s;
        e=_e;
    }
    Line(Point p,double angle){
        s=p;
        if (sgn(angle-pi/2)==0) e=(s+Point(0,1));
        else e=(s+Point(1,tan(angle)));
    }
    Line(double a,double b,double c){
        if (sgn(a)==0){
            s=Point(0,-c/b);
            e=Point(1,-c/b);
        }
        else if (sgn(b)==0){
            s=Point(-c/a,0);
            e=Point(-c/a,1);
        }
        else{
            s=Point(0,-c/b);
            e=Point(1,(-c-a)/b);
        }
    }
    void input(){
        s.input();
        e.input();
    }
    int segcrossseg(Line v){
        int d1=sgn((e-s)^(v.s-s));
        int d2=sgn((e-s)^(v.e-s));
        int d3=sgn((v.e-v.s)^(s-v.s));
        int d4=sgn((v.e-v.s)^(e-v.s));
        if ((d1^d2)==-2 && ((d3^d4)==-2) ) return 2;
        return ((d1==0&&sgn((v.s-s)*(v.s-e))<=0) ||
                (d2==0&&sgn((v.e-s)*(v.e-e))<=0) ||
                (d3==0&&sgn((s-v.s)*(s-v.e))<=0) ||
                (d4==0&&sgn((e-v.s)*(e-v.e))<=0));
    }
    Point crosspoint(Line v){
        double a1=(v.e-v.s)^(s-v.s);
        double a2=(v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
};

Point A,B,C,D,M;
Line AB,CD,AC,BD,AD,BC;
double ans;

double calc(Point x){
    return A.distance(x)+B.distance(x)+C.distance(x)+D.distance(x);
}

int main(){
    //freopen("input.txt","r",stdin);
    while(1){
        A.input();B.input();C.input();D.input();
        if (A.x==-1&&A.y==-1&&B.x==-1&&B.y==-1&&C.x==-1&&C.y==-1&&D.x==-1&&D.y==-1) break;
        ans=inf;
        ans=min(ans,calc(A));
        ans=min(ans,calc(B));
        ans=min(ans,calc(C));
        ans=min(ans,calc(D));
        AB=Line(A,B);
        CD=Line(C,D);
        if (AB.segcrossseg(CD)>0){
            M=AB.crosspoint(CD);
            ans=min(ans,calc(M));
        }
        AC=Line(A,C);
        BD=Line(B,D);
        if (AC.segcrossseg(BD)>0){
            M=AC.crosspoint(BD);
            ans=min(ans,calc(M));
        }
        AD=Line(A,D);
        BC=Line(B,C);
        if (AD.segcrossseg(BC)>0){
            M=AD.crosspoint(BC);
            ans=min(ans,calc(M));
        }
        printf("%.4lf\n",ans);
    }
    return 0;
}