“模拟退火”,也是胡整算法吧,不过确实很好用
题目范围不大,精度要求不高,枚举,将整个连续空间离散分成1000个每个相距0.1的点,枚举每个点,能找到答案,复杂度高,是可以优化的
二分,每次枚举9个点 ( 正方形平均的9个点 ),找到最有点后再以这个点为九个点的中心点缩小步长再尝试9个点,直到枚举的两点间相差<0.01
求出一个点到某线段的最短距离,要分两种情况:
一是这个点做垂线会落到这个线段上,这种情况用差乘求出这个点与线段构成的三角形面积*2,然后再除以这个线段的长度就是垂线的长度:
二是这个点对线段做出的垂线在线段外,那么最短的距离只可能是到线段两个端点距离的最短那个。判断钝角三角形(x1^2+x2^2<x3^2,代表x1与x2的夹角是钝角)
/*
PROG:fence3
ID:xsy97051
LANG:C++
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define INF 2000000005
struct node
{
double x0,y0,x1,y1,len;
} line[152];
double ansx,ansy,ans,len,step;
double MaxX,MaxY,StartX,StartY;
double dis(node a,double x,double y)
{
double x1,y1,x2,y2;
x1=(x-a.x0)*(x-a.x0)+(y-a.y0)*(y-a.y0);
x2=(x-a.x1)*(x-a.x1)+(y-a.y1)*(y-a.y1);
if(x1-x2-a.len*a.len>-0.001 || x2-x1-a.len*a.len>-0.001)
{
if(x1<x2) return sqrt(x1);
else return sqrt(x2);
}
x1=x-a.x0;
y1=y-a.y0;
x2=a.x1-a.x0;
y2=a.y1-a.y0;
double tep=x1*y2-x2*y1;
if(tep<0) tep=-tep;
return tep/a.len;
}
int main()
{
freopen("fence3.in","r",stdin);
freopen("fence3.out","w",stdout);
StartX=StartY=INF;
MaxX=MaxY=-INF;
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&line[i].x0,&line[i].y0,&line[i].x1,&line[i].y1);
line[i].len=sqrt((line[i].x0-line[i].x1)*(line[i].x0-line[i].x1)+(line[i].y0-line[i].y1)*(line[i].y0-line[i].y1));
if(line[i].x1<line[i].x0)
swap(line[i].x1,line[i].x0);
if(line[i].y1<line[i].y0)
swap(line[i].y1,line[i].y0);
if(line[i].x1>MaxX) MaxX=line[i].x1;
if(line[i].x0<StartX) StartX=line[i].x0;
if(line[i].y1>MaxY) MaxY=line[i].y1;
if(line[i].y0<StartY) StartY=line[i].y0;
}
if(MaxY>MaxX) len=MaxY/2;
else len=MaxX/2;
ans=INF;
ans*=ans;
while(len>0.01)
{
step=len/4;
MaxX=StartX+len;
MaxY=StartY+len;
for(double x=StartX;x<=MaxX;x+=step)
for(double y=StartY;y<=MaxY;y+=step)
{
double now=0;
for(int i=1;i<=n;i++)
{
now+=dis(line[i],x,y);
if(now>ans) break;
}
if(now<ans)
{
ans=now;
ansx=x;
ansy=y;
}
}
StartX=ansx-step/2;
StartY=ansy-step/2;
len/=2;
}
printf("%.1lf %.1lf %.1lf\n",ansx,ansy,ans);
return 0;
}