传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1038
一开始以为只能在顶点修,然后就开开心心枚举+二分,发现样例都过不了= = 、
然后又不会半平面交,那就模拟退火骗分吧,开开心心写了模拟退火,拿来数据一测, 30 ,然后又开开心心的对着数据调参数= =、
Code:
#include<bits/stdc++.h>
#define rnd ((double)rand()/RAND_MAX)
using namespace std;
const int maxn=305;
const double eps=1e-7;
int dcmp(double x){
if(fabs(x)<eps)return 0;
return x>0?1:-1;
}
double x[maxn],y[maxn];
int n;
bool ok(double X,double h){
double Y;
int pre,suc;
suc=lower_bound(x+1,x+1+n,X)-x;
pre=suc-1;
Y=y[pre]+(X-x[pre])*(y[suc]-y[pre])/(x[suc]-x[pre]);
for(int i=2;i<=pre;i++){
if((Y+h-y[i])*(x[i]-x[i-1])<(y[i]-y[i-1])*(X-x[i]))return 0;
}
for(int i=suc;i<n;i++){
if((y[i]-Y-h)*(x[i+1]-x[i])>(y[i+1]-y[i])*(x[i]-X))return 0;
}return 1;
}
double ans=1e11;
double getans(double X){
double l=0,r=1e11;
int m=200;
while(dcmp(l-r)&&m){
m--;
double mid=(l+r)*.5;
if(ok(X,mid))
r=mid;
else
l=mid;
}ans=min(ans,l);
return l;
}
int main(){
srand(10086);
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lf",x+i);
for(int i=1;i<=n;i++)scanf("%lf",y+i);
int m=1;
while(m--){
double X=x[1]+(x[n]-x[1])*rnd;
double an=getans(X);
double T=x[n]-x[1],res;
while(T>1e-8){
T/=2;
if(X+T<=x[n]){
res=getans(X+T);
if(dcmp(res-an)<0){
an=res;
X=X+T;
}
}
if(X-T>=x[1]){
res=getans(X-T);
if(dcmp(res-an)<0){
an=res;
X=X-T;
}
}
T*=2;
T*=0.96;
}
}
printf("%.3lf\n",ans);
return 0;
}