您的位置:首页 > 其它

[BZOJ1038][ZJOI2008]瞭望塔(半平面交)

2017-04-05 10:17 260 查看

=== ===

这里放传送门

=== ===

题解

可以发现对于一个山坡来说,建造的瞭望塔能看到它的条件就是塔顶连接山谷的那条线的斜率绝对值大于山坡斜率的绝对值,如图:



1号和3号山坡是可以被看到的,而2号不可以。

我们可以发现只要把所有的山坡向上做半平面交,瞭望塔的顶点一定要在交集内部。可以发现最小高度的瞭望塔至少有一个顶点在凸多边形或山坡的顶点上,那么为了求出最小的高度,我们可以用O(n2)的时间枚举凸多边形和山坡的所有顶点和边来计算高度,也可以用两个指针扫一下。

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const double eps=1e-12;
const double inf=1e10;
int n;
double ans;
struct Vector{
double x,y;
Vector(double X=0,double Y=0){x=X;y=Y;}
Vector operator + (const Vector &a){return Vector(x+a.x,y+a.y);}
Vector operator - (const Vector &a){return Vector(x-a.x,y-a.y);}
double operator * (const Vector &a){return x*a.y-y*a.x;}
Vector mul(double t){return Vector(x*t,y*t);}
}v[310],tmp,w,ip;
int comp(Vector a,Vector b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
struct Polygon{
Vector p[500];
int c;
Polygon(){c=0;memset(p,0,sizeof(p));}
void clear(){
p[1]=Vector(-inf,inf);
p[2]=Vector(-inf,-inf);
p[3]=Vector(inf,-inf);
p[4]=Vector(inf,inf);
p[5]=p[1];c=4;
}
void add(Vector v){p[++c]=v;}
void Sort(){sort(p+1,p+c+1,comp);}
}poly;
bool Ins(Vector A,Vector B,Vector C,Vector D){
Vector v=B-A,w=D-C,u=D-A;
if (fabs(w*v)<eps) return false;
w=C-A;
return ((v*w)*(v*u)<-eps);
}
Vector GLI(Vector P,Vector v,Vector Q,Vector w){
Vector u=P-Q;
double t=(w*u)/(v*w);
return P+v.mul(t);
}
Polygon CutPolygon(Polygon poly,Vector A,Vector B){
Vector C,D,ip;
Polygon newp=Polygon();
for (int i=1;i<=poly.c;i++){
C=poly.p[i];D=poly.p[i+1];
if ((B-A)*(C-A)>-eps) newp.add(C);
if (Ins(A,B,C,D)){
ip=GLI(A,B-A,C,D-C);
newp.add(ip);
}
}
newp.p[newp.c+1]=newp.p[1];
return newp;
}
int main()
{
scanf("%d",&n);poly.clear();
for (int i=1;i<=n;i++) scanf("%lf",&v[i].x);
for (int i=1;i<=n;i++) scanf("%lf",&v[i].y);
for (int i=1;i<n;i++)
poly=CutPolygon(poly,v[i],v[i+1]);
v[0]=Vector(-inf,-inf);v[n+1]=Vector(inf,-inf);
poly.Sort();w=Vector(0,1);ans=1e60;
for (int i=1,ptr=0;i<=poly.c;i++){
tmp=poly.p[i];
while (ptr<=n&&v[ptr].x<tmp.x) ++ptr;
if (ptr>n) break;//注意不能计算斜线段
ip=GLI(tmp,w,v[ptr-1],v[ptr]-v[ptr-1]);
if (ip.x-v[1].x>-eps&&v
.x-ip.x>-eps)
ans=min(ans,fabs(ip.y-tmp.y));
}
poly.p[0]=Vector(-inf,inf);
poly.p[poly.c+1]=Vector(inf,inf);
for (int i=1,ptr=0;i<=n;i++){
tmp=v[i];
while (ptr<=poly.c&&poly.p[ptr].x<tmp.x) ++ptr;//找到顶点正下方的线段
if (ptr>poly.c) break;
ip=GLI(tmp,w,poly.p[ptr-1],poly.p[ptr]-poly.p[ptr-1]);
ans=min(ans,fabs(ip.y-tmp.y));
}
printf("%.3lf\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息