URAL-1451. Beerhouse Tale

1、知识点:费马点
2、思路:下面是百度百科对费马点的解释,也是解题思路:
① 若三角形3个内角均小于120°,那么3条距离连线正好三等分费马点所在的周角,即该点所对三角形三边的张角相等,均为120°。所以三角形的费马点也称为三角形的等角中心。
(托里拆利的解法中对这个点的描述是:对于每一个角都小于120°的三角形ABC的每一条边为底边,向外作正三角形,然后作这三个正三角形的外接圆。托里拆利指出这三个外接圆会有一个共同的交点,而这个交点就是所要求的点。这个点和当时已知的三角形特殊点都不一样。这个点因此也叫做托里拆利点。)
② 若三角形有一内角大于等于120°,则此钝角的顶点就是距离和最小的点。

/*用途:
**说明:
**算法:
*/

//#define LOCAL
#include <cstdio>
#include <cmath>
using namespace std;
#define MAXN 3
#define PREC 0.00000001

struct point{
    double x, y; 
};

point poi[MAXN];
point ans;

int main()
{
#ifdef LOCAL
    freopen(".in", "r", stdin);
    freopen(".out", "w", stdout);
#endif

    for(int i=0; i<MAXN; i++)
        scanf("%lf %lf", &(poi[i].x), &(poi[i].y));

    double c, b, a;  //AB、AC、BC对应三边
    a = sqrt(pow(poi[1].x-poi[2].x, 2) + pow(poi[1].y-poi[2].y, 2));
    b = sqrt(pow(poi[0].x-poi[2].x, 2) + pow(poi[0].y-poi[2].y, 2));
    c = sqrt(pow(poi[0].x-poi[1].x, 2) + pow(poi[0].y-poi[1].y, 2));

    double cosA, cosB, cosC;
    cosA = (b*b+c*c-a*a) / (2*b*c);
    cosB = (a*a+c*c-b*b) / (2*a*c);
    cosC = (a*a+b*b-c*c) / (2*a*b);

    //任意角>=120度 
    if(cosA <= -0.5){
        printf("%.8lf %.8lf", poi[0].x, poi[0].y);
        return 0;
    }
    else if(cosB <= -0.5){
        printf("%.8lf %.8lf", poi[1].x, poi[1].y);
        return 0;
    }
    else if(cosC <= -0.5){
        printf("%.8lf %.8lf", poi[2].x, poi[2].y);
        return 0;
    }

    point or_c, or_c1, or_c2, or_b, or_b1, or_b2;
    point mid_c, mid_b;
    mid_c.x = (poi[0].x+poi[1].x) / 2;
    mid_c.y = (poi[0].y+poi[1].y) / 2;
    mid_b.x = (poi[0].x+poi[2].x) / 2;
    mid_b.y = (poi[0].y+poi[2].y) / 2;

    double k_AB, k_AC;
    k_AB = (poi[0].y-poi[1].y) / (poi[0].x-poi[1].x);
    k_AC = (poi[0].y-poi[2].y) / (poi[0].x-poi[2].x);

    //求AB边外接圆心 
    if(fpclassify(k_AB) == FP_INFINITE){    //k_AB不存在 
        or_c1.x = mid_c.x - c/sqrt(12);
        or_c1.y = mid_c.y;
        or_c2.x = mid_c.x + c/sqrt(12);
        or_c2.y = mid_c.y;
    }
    else if(k_AB == 0){   //k_AB=0 
        or_c1.x = mid_c.x;
        or_c1.y = mid_c.y + c/sqrt(12);
        or_c2.x = mid_c.x;
        or_c2.y = mid_c.y - c/sqrt(12);
    }
    else{   //k_AB存在 且不为0 
        or_c1.x = mid_c.x - c/sqrt(12)*k_AB/sqrt(k_AB*k_AB+1);
        or_c1.y = mid_c.y - 1.0/k_AB*(or_c1.x-mid_c.x);
        or_c2.x = mid_c.x + c/sqrt(12)*k_AB/sqrt(k_AB*k_AB+1);
        or_c2.y = mid_c.y - 1.0/k_AB*(or_c2.x-mid_c.x);
    }

    double v1 = (or_c1.x-mid_c.x)*(poi[2].x-poi[0].x) + (or_c1.y-mid_c.y)*(poi[2].y-poi[0].y);
    if(v1 < PREC){      //如果or_c1在三角形外部 
        or_c.x = or_c1.x;
        or_c.y = or_c1.y;
    }
    else{
        or_c.x = or_c2.x;
        or_c.y = or_c2.y;
    }

    //求AC边外接圆心 
    if(fpclassify(k_AC) == FP_INFINITE){   //k_AC不存在 
        or_b1.x = mid_b.x - b/sqrt(12);
        or_b1.y = mid_b.y;
        or_b2.x = mid_b.x + b/sqrt(12);
        or_b2.y = mid_b.y;
    }
    else if(k_AC == 0){
        or_b1.x = mid_b.x;
        or_b1.y = mid_b.y + b/sqrt(12);
        or_b2.x = mid_b.x;
        or_b2.y = mid_b.y - b/sqrt(12);
    }
    else{   //k_AC存在 
        or_b1.x = mid_b.x - b/sqrt(12)*k_AC/sqrt(k_AC*k_AC+1);
        or_b1.y = mid_b.y - 1.0/k_AC*(or_b1.x-mid_b.x);
        or_b2.x = mid_b.x + b/sqrt(12)*k_AC/sqrt(k_AC*k_AC+1);
        or_b2.y = mid_b.y - 1.0/k_AC*(or_b2.x-mid_b.x);
    }

    double v2 = (or_b1.x-mid_b.x)*(poi[1].x-poi[0].x) + (or_b1.y-mid_b.y)*(poi[1].y-poi[0].y);
    if(v2 < PREC){      //如果or_b1在三角形外部 
        or_b.x = or_b1.x;
        or_b.y = or_b1.y;
    }
    else{
        or_b.x = or_b2.x;
        or_b.y = or_b2.y;
    }

    //求经过or_b,or_c 两点的直线,并求点A关于直线的对称点 
    double k_oo = (or_b.y-or_c.y) / (or_b.x-or_c.x); 
    if(fpclassify(k_oo) == FP_INFINITE){    //如果圆心连线斜率不存在 
        ans.x = 2*or_b.x - poi[0].x;
        ans.y = poi[0].y;
    }
    else if(fabs(k_oo) < PREC){     //如果斜率为0 
        ans.x = poi[0].x;
        ans.y = 2*or_b.y - poi[0].y;
    }
    else{                           //斜率存在且不为0 
        ans.x = (2*poi[0].y+(1.0/k_oo-k_oo)*poi[0].x-2*(or_c.y-k_oo*or_c.x)) / (k_oo+1.0/k_oo);
        ans.y = poi[0].y-1.0/k_oo*(ans.x-poi[0].x);
    }

    printf("%.8lf %.8lf", ans.x, ans.y);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值