• 【bzoj1038】瞭望塔 半平面交


    题目描述

    致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。我们将H村抽象为一维的轮廓。如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长希望建造的塔高度尽可能小。请你写一个程序,帮助dadzhi村长计算塔的最小高度。

    输入

    第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1 ~ yn。

    输出

    仅包含一个实数,为塔的最小高度,精确到小数点后三位。

    样例输入

    【输入样例一】
    6
    1 2 4 5 6 7
    1 2 2 4 2 1
    【输入样例二】
    4
    10 20 49 59
    0 10 10 0

    样例输出

    【输出样例一】
    1.000
    【输出样例二】
    14.500


    题解

    半平面交

    首先由于要看到所有点,因此选择的塔顶要在所有直线之上。因此求所有直线的上半平面的半平面交即为塔顶的范围。

    由于要让塔的高度尽量小,因此塔顶的位置一定在半平面交下半部分的边上。

    因此对于一个x,塔的高度就是 该点半平面交部分的高度-该点山的高度 。由于这两部分都是折线,作差也是折线。折线的最值只在拐点处取到,因此只需要枚举拐点位置即可。

    细节超多又卡精。。。半平面交只能求封闭的凸多边形,因此需要在左、上、右各添加辅助线;辅助线不能影响半平面的范围,因此需要在山的左右端点处添加;辅助线的斜率不能是inf,因此不能与x轴垂直。

    具体还是看代码吧。

    时间复杂度 $O(nlog n)$ 

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 310
    #define eps 1e-9
    using namespace std;
    typedef long double ld;
    struct point
    {
    	ld x , y;
    	point() {}
    	point(ld a , ld b) {x = a , y = b;}
    	point operator+(const point &a)const {return point(x + a.x , y + a.y);}
    	point operator-(const point &a)const {return point(x - a.x , y - a.y);}
    	point operator*(const ld &a)const {return point(x * a , y * a);}
    	bool operator<(const point &a)const {return x < a.x;}
    }p[N] , c[N];
    struct line
    {
    	point p , v;
    	ld ang;
    }a[N] , q[N];
    inline ld cross(point a , point b) {return a.x * b.y - a.y * b.x;}
    inline bool left(line a , point b) {return cross(a.v , b - a.p) > eps;}
    inline point inter(line a , line b)
    {
    	point u = a.p - b.p;
    	ld tmp = cross(b.v , u) / cross(a.v , b.v);
    	return a.p + a.v * tmp;
    }
    bool cmp(const line &a , const line &b)
    {
    	return fabs(a.ang - b.ang) < eps ? left(a , b.p) :  a.ang < b.ang;
    }
    int main()
    {
    	int n , i , l = 1 , r = 1 , t , tot = 1;
    	ld ans = 1e20;
    	scanf("%d" , &n);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%Lf" , &p[i].x);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%Lf" , &p[i].y);
    	for(i = 1 ; i < n ; i ++ ) a[i].p = p[i] , a[i].v = p[i] - p[i + 1] , a[i].ang = atan2(a[i].v.y , a[i].v.x);
    	a[n].p = point(0 , 1e20) , a[n].v = point(1 , 0) , a[n].ang = 0;
    	a[n + 1].p = point(p[1].x , p[1].y) , a[n + 1].v = point(-1e-10 , 1) , a[n + 1].ang = atan2(1 , 0);
    	a[n + 2].p = point(p[n].x , p[n].y) , a[n + 2].v = point(1e-10 , -1) , a[n + 2].ang = atan2(-1 , 0);
    	sort(a + 1 , a + n + 3 , cmp);
    	for(i = 2 ; i <= n + 2 ; i ++ )
    		if(fabs(a[i].ang - a[i - 1].ang) > eps)
    			a[++tot] = a[i];
    	q[1] = a[1];
    	for(i = 2 ; i <= tot ; i ++ )
    	{
    		while(l < r && left(a[i] , c[r - 1])) r -- ;
    		while(l < r && left(a[i] , c[l])) l ++ ;
    		q[++r] = a[i];
    		if(l < r) c[r - 1] = inter(q[r - 1] , q[r]);
    	}
    	while(l < r && left(q[l] , c[r - 1])) r -- ;
    	c[r] = inter(q[r] , q[l]);
    	sort(c + l , c + r + 1);
    	for(i = 1 , t = l ; i <= n ; i ++ )
    	{
    		while(t < r && c[t + 1] < p[i]) t ++ ;
    		ans = min(ans , (p[i].x - c[t].x) * (c[t + 1].y - c[t].y) / (c[t + 1].x - c[t].x) + c[t].y - p[i].y);
    	}
    	for(i = l , t = 1 ; i <= r ; i ++ )
    	{
    		if(c[i] < p[1] || p[n] < c[i]) continue;
    		while(t < n && p[t + 1] < c[i]) t ++ ;
    		ans = min(ans , c[i].y - (c[i].x - p[t].x) * (p[t + 1].y - p[t].y) / (p[t + 1].x - p[t].x) - p[t].y);
    	}
    	printf("%.3Lf
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    hdu2222 AC自动机入门
    bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
    【NOI2014】起床困难综合症 贪心
    bzoj1822: [JSOI2010]Frozen Nova 冷冻波网络流
    洛谷3767 膜法 带权并查集+分治
    NOI2015品酒大会 后缀数组
    NOI2015程序自动分析 并查集
    NOI2015软件包管理器 树剖线段树
    51nod1244 欧拉函数之和 杜教筛
    51nod1244 莫比乌斯函数之和 杜教筛
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8072470.html
Copyright © 2020-2023  润新知