瞭望塔-半平面交

瞭望塔-半平面交

题目描述

题目描述

题解

首先维护出所有直线的半平面交(注意加边界),所有直线的半平面交是一个下凸壳,然后发现瞭望塔的横坐标一定是下凸壳中顶点的横坐标,或原村庄点的横坐标,O(n)扫一遍更新答案

代码实现(一直90分,不知哪里挂了)

#include<bits/stdc++.h>
#define M 100009
using namespace std;
int tot,cnt,num,n;
double ans=1e+17;//ans初始值尽量大(坑点) 
const double eps=1e-10;//注意精度 
struct point{
	double x,y;
	point(double a=0,double b=0){x=a,y=b;}
	friend inline point operator+(const point &a,const point &b){return point(a.x+b.x,a.y+b.y);}
	friend inline point operator-(const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}
	friend inline double operator*(const point &a,const point &b){return a.x*b.y-b.x*a.y;}
	friend inline double operator^(const point &a,const point &b){return a.x*b.x+a.y*b.y;}
	friend inline point operator/(const point &a,const double &b){return point(a.x/b,a.y/b);}
	friend inline point operator%(const point &a,const double &b){return point(a.x*b,a.y*b);}
	inline double dist(){return sqrt(x*x+y*y);}
}p[M],q[M],w[M];
struct line{
	point a,b;
	double slop;
}l[M],s[M];
bool cmp(const line &a,const line &b){
	if(fabs(a.slop-b.slop)>eps) return a.slop+eps<b.slop;
	else return (a.b-a.a)*(b.b-a.a)<eps;
}
bool comp(const point &a,const point &b){return a.x+eps<b.x;}
bool jud(point y,line x){return (y-x.a)*(x.b-x.a)>eps;}
point inter(line a,line b){
	double k1,k2,t;
	k1=(b.b-a.a)*(a.b-a.a);
	k2=(a.b-a.a)*(b.a-a.a);
	t=k1/(k1+k2);
	return point(b.b.x+(b.a.x-b.b.x)*t,b.b.y+(b.a.y-b.b.y)*t);
}
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[++cnt].a=p[i],l[cnt].b=p[i+1];
	l[++cnt].b=point(p[1].x,1e+12),l[cnt].a=point(p[n].x,1e+12); 
	l[++cnt].b=p[1],l[cnt].a=point(p[1].x,1e+12); 
	l[++cnt].a=p[n],l[cnt].b=point(p[n].x,1e+12); //加边界 
	for(int i=1;i<=cnt;i++) l[i].slop=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);
	sort(l+1,l+cnt+1,cmp);
	for(int i=1;i<=cnt;i++){
		if(l[i].slop!=l[i-1].slop) tot++;
		l[tot]=l[i];
	}cnt=tot;tot=0;//去掉斜率相同而无用的直线 
	int L=1,R=0;
	for(int i=1;i<=cnt;i++){
		while(R>L&&jud(q[R-1],l[i])) R--;
		while(R>L&&jud(q[L],l[i])) L++;
		s[++R]=l[i];
		if(R>L) q[R-1]=inter(s[R],s[R-1]);
	}
	while(R>L&&jud(q[R-1],s[L])) R--;
	//while(R>L&&jud(q[L],s[R])) L++;
	if(R>L) q[R]=inter(s[R],s[L]);
	for(int i=L;i<=R;i++) w[++tot]=q[i];
	sort(w+1,w+tot+1,comp);
	num=1;
	for(int i=2;i<=tot;i++)
		if(w[i].y<1e+11) w[++num]=w[i];//去掉边界点	
	int w1=1,w2=2;
	p[0].x=p[1].x-1;
	w[0].x=w[1].x-1;
	while (w1<=num||w2<=n){//O(n)扫一遍更新答案 
        if (w2>n||(w1<=num&&w[w1].x<p[w2].x)){
            point t=p[w2-1]+(p[w2]-p[w2-1])/(p[w2].x-p[w2-1].x)%(w[w1].x-p[w2-1].x);
            ans=min(ans,w[w1].y -t.y);
            w1++;
        }
        else{
            point t=w[w1-1]+(w[w1]-w[w1-1])/(w[w1].x-w[w1-1].x)%(p[w2].x-w[w1-1].x);
            ans = min(ans,t.y-p[w2].y);
            w2++;
        }
    }printf("%.3lf\n",ans);
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值