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\n",-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\n",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\n",p.first,p.second);
    return 0;
}
  • 公式推导:

\[\begin{aligned} &A=\left(b^{2}-a^{2}\right) \cdot x_{1}-2 \cdot a \cdot b \cdot y_{1}+2 \cdot a \cdot c\\ &B=\left(a^{2}-b^{2}\right) \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 \cdot\left(c-b \cdot y_{2}\right)\\ &G=D \cdot a \cdot y_{2}+E \cdot\left(c-a \cdot x_{2}\right)\\ &H=a \cdot D+b \cdot E \end{aligned} \]

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

#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;
}
posted @ 2020-03-26 19:39  QFNU-ACM  阅读(200)  评论(0编辑  收藏  举报