BZOJ 1038: [ZJOI2008]瞭望塔(半平面交)

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/88943135

题目
对于每个坡,能看到它的范围为一个半平面,做半平面交得到一个下凸壳。
发现答案一定在下凸壳的顶点或折线的顶点处取。

AC Code:

#include<bits/stdc++.h>
#define maxn 1005
#define eps 1e-8
using namespace std;

int n;
struct Point{
	double x,y;
	Point (double x=0,double y=0):x(x),y(y){}
	Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
	Point operator +(const Point &B)const{ return Point(x+B.x,y+B.y); }
	double operator *(const Point &B)const{ return x*B.y-y*B.x; }
	Point operator *(const double &B)const{ return Point(x*B,y*B); }
}P[maxn];

struct Line{
	Point A,B;
	double ag;
}L[maxn];
int id[maxn],tot,qL[maxn],l,r;
Point qp[maxn];
inline int sgn(double a){ return a<-eps?-1:a>eps?1:0; }
inline bool inLeft(const Point &P,const Point &A,const Point &B){
	return sgn((B-A)*(P-A))==1;
}
inline bool onLeft(const Point &P,const Point &A,const Point &B){
	return sgn((B-A)*(P-A))>=0;
}
inline bool cmp(const int &u,const int &v){
	if(sgn(L[u].ag-L[v].ag)) return L[u].ag<L[v].ag;
	return inLeft(L[u].A,L[v].A,L[v].B);
}
Point Ipt(const Point &p1,const Point &p2,const Point &p3,const Point &p4){
	Point u=p2-p1,v=p4-p3,w=p2-p4;
	return p2+(p1-p2)*((w*v)/(u*v));
}



int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%lf",&P[i].x);
	for(int i=1;i<=n;i++) scanf("%lf",&P[i].y);
	for(int i=1;i<n;i++){
		L[++tot].A=P[i],L[tot].B=P[i+1];
		L[tot].ag=atan2(P[i+1].y-P[i].y,P[i+1].x-P[i].x);
		id[tot]=tot;
	}
	sort(id+1,id+1+tot,cmp);
	qL[r++] = id[1];
	for(int i=2,u;i<=tot;i++)
		if(sgn(L[u=id[i]].ag-L[id[i-1]].ag)){
			for(;r-l>=2 && !onLeft(qp[r-2],L[u].A,L[u].B);r--);
			for(;r-l>=2 && !onLeft(qp[l],L[u].A,L[u].B);l++);
			qL[r++] = u;
			if(r-l>=2)
				qp[r-2] = Ipt(L[qL[r-2]].A,L[qL[r-2]].B,L[u].A,L[u].B);
		}
	for(;r-l>=2 && !onLeft(qp[r-2],L[qL[l]].A,L[qL[l]].B);r--);
	int k = l;
	double ans = 2e17;
	for(int i=1;i<=n;i++){
		for(;k<=r-2 && qp[k].x<P[i].x;k++);
		ans = min(ans , max(0.0,Ipt(Point(P[i].x,0),Point(P[i].x,1),L[qL[k]].A,L[qL[k]].B).y - P[i].y));
	}
	k = 2;
	for(int i=l;i<=r-2;i++){
		for(;k<=n && P[k].x <= qp[i].x;k++);
		if(k<=n)
			ans = min(ans , max(0.0,qp[i].y-Ipt(Point(qp[i].x,0),Point(qp[i].x,1),P[k-1],P[k]).y));
		else 
			break;
	}
	printf("%.3lf\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/88943135