题解 P2600 【[ZJOI2008]瞭望塔】
我不会什么半平面交,也不想写队列,我只用最暴力的方法AC此题
首先通过手动模拟可以得到一个结论:
瞭望塔的横坐标一定在两条直线的交点处
所以我们先利用开始的n个点求出n-1条直线
然后两两枚举求交点的横坐标。
对于每一个横坐标再通过枚举n-1条直线求最高点
然后答案取一个最小值即可
复杂度
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef double db;
const int N=305;
const db inf=99999999999.0;
int n;
db ax[N],ay[N];
struct LINE{
db k,b; //y=kx+b
}ln[N];
db ans=inf;
db sol(db x){ //计算特定横坐标的最小瞭望塔高度
db res=0;
for(int i=1;i<n;i++)
res=max(res,ln[i].k*x+ln[i].b);
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf",&ax[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&ay[i]);
for(int i=1;i<n;i++){
ln[i].k=(ay[i]-ay[i+1])/(ax[i]-ax[i+1]);
ln[i].b=ay[i]-ln[i].k*ax[i];
}
for(int i=1;i<=n;i++)
ans=min(ans,sol(ax[i])-ay[i]); //先枚举每个端点
for(int i=1;i<n;i++)
for(int j=i+1;j<n;j++){
db x=(ln[i].b-ln[j].b)/(ln[j].k-ln[i].k); //求两直线的交点
for(int k=1;k<n;k++)
if(ax[k]<=x&&x<=ax[k+1])
ans=min(ans,sol(x)-ln[k].k*x-ln[k].b); //最小化答案
}
printf("%.3lf\n",ans);
return 0;
}