zoukankan      html  css  js  c++  java
  • 3.26 每日一题题解

    题目链接

    I. 题意

    给定两个点 ((x_1,y_1), (x_2,y_2)) 和一条直线 (ax+by=c),求直线上一点使得到这两个点的距离之和最小。

    II. 题解

    显然,要找的点就是两点之一关于直线的对称点与另一点连接直线与原直线的交点;

    • 不难发现在直线上寻找这样的点,距离之和的函数是下凹的,所以可以三分法求单峰函数的极值;(不过这个单峰函数的三分损失精度比较大,很难达到题目要求的精度,这里只讨论方法)
    #include<bits/stdc++.h>
    using namespace std;
    const double eps = 1e-12;
    #define zero(x) ((fabs(x) < eps ? 1 : 0))
    double x1,y_1,x2,y2,a,b,c;
    double gety(double x)
    {
        return c/b-a/b*x;
    }
    double dis(double x1,double y1,double x2,double y2)
    {
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
      
    int main()
    {
        cin>>x1>>y_1>>x2>>y2>>a>>b>>c;
        if(zero(b))
        {
            double l=-1e8,r=1e8,mid, mmid;
            while(r-l > eps)
            {
                mid = (r+l)/2.0;
                mmid = (mid+r)/2.0;
                if(dis(x1,y_1,-c/a,mid)+dis(x2,y2,-c/a,mid)
                    < dis(x1,y_1,-c/a,mmid)+dis(x2,y2,-c/a,mmid)) r = mmid;
                else l = mid;
            }
            printf("%.12f %.12f
    ",-c/a,l);
        }
        else
        {
            double l=-1e8,r=1e8,mid, mmid;
            while(r-l > eps)
            {
                mid = (r+l)/2.0;
                mmid = (mid+r)/2.0;
                if(dis(x1,y_1,mid,gety(mid))+dis(x2,y2,mid,gety(mid))
                    < dis(x1,y_1,mmid,gety(mmid))+dis(x2,y2,mmid,gety(mmid))) r = mmid;
                else l = mid;
            }
            printf("%.12f %.12f
    ",l,gety(l));
        }
        return 0;
    }
    
    • 直接计算几何模板求解;
    #include<bits/stdc++.h>
    using namespace std;
     
    pair<double ,double> getp(double a1,double b1,double c1,
                              double a2,double b2,double c2)
    {
        return {(b1*c2-b2*c1)/(a1*b2-a2*b1),(a2*c1-a1*c2)/(a1*b2-a2*b1)};
    }
    double dis(double a,double b,double c,double x,double y)
    {
        return fabs(a*x+b*y+c)/sqrt(a*a+b*b);
    }
     
    int main()
    {
        double x_1,y_1,x_2,y_2,a,b,c;
        cin>>x_1>>y_1>>x_2>>y_2>>a>>b>>c;
        c*=(-1.0);
        double x_3=x_1-a/sqrt(a*a+b*b)*2*dis(a,b,c,x_1,y_1);
        double y_3=y_1-b/sqrt(a*a+b*b)*2*dis(a,b,c,x_1,y_1);
        double a1=y_2-y_3,b1=x_3-x_2,c1=y_3*(x_2-x_3)-x_3*(y_2-y_3);
        auto p=getp(a,b,c,a1,b1,c1);
        printf("%.13f %.13f
    ",p.first,p.second);
        return 0;
    }
    
    • 公式推导:

    [egin{aligned} &A=left(b^{2}-a^{2} ight) cdot x_{1}-2 cdot a cdot b cdot y_{1}+2 cdot a cdot c\ &B=left(a^{2}-b^{2} ight) cdot y_{1}-2 cdot a cdot b cdot x_{1}+2 cdot b cdot c\ &C=a^{2}+b^{2}\ &D=C cdot x_{2}-A\ &E=C cdot y_{2}-B\ &F=E cdot b cdot x_{2}+D cdotleft(c-b cdot y_{2} ight)\ &G=D cdot a cdot y_{2}+E cdotleft(c-a cdot x_{2} ight)\ &H=a cdot D+b cdot E end{aligned} ]

    答案就是 (left(frac{F}{H},frac{G}{H} ight)).

    #include<bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        double x1,x2,y1,y2,a,b,c;
        cin>>x1>>y1>>x2>>y2>>a>>b>>c;
        double A=(b*b-a*a)*x1-2*a*b*y1+2*a*c;
        double B=(a*a-b*b)*y1-2*a*b*x1+2*b*c;
        double C=(a*a+b*b)*x2-A,D=(a*a+b*b)*y2-B;
        double E=D*b*x2+C*(c-b*y2);
        double F=C*a*y2+D*(c-a*x2);
        printf("%.12f %.12f",E/(a*C+b*D),F/(a*C+b*D));
        return 0;
    }
    
  • 相关阅读:
    [转载] 关于mkvtoolnix批量处理的
    转载:JMeter压力测试入门教程[图文]
    分享 stormzhang的Andoid学习之路
    Sublime Text 2 插件
    PHP 操作SQLite
    curl 远程下载图片
    centos lamp 配置
    php 例子 如何转换ISO8601为 utc时间
    php 常用 常量集合
    php 文档操作
  • 原文地址:https://www.cnblogs.com/QFNU-ACM/p/12576791.html
Copyright © 2011-2022 走看看