zoukankan      html  css  js  c++  java
  • 「BZOJ1038」「洛谷P2600」「ZJOI2008」瞭望塔 半平面交+贪心

    题目链接

    BZOJ/洛谷

    题目描述

    致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。
    我们将H村抽象为一维的轮廓。如下图所示:

    我们可以用一条山的上方轮廓折线((x_1,y_1),(x_2,y_2)…(x_n,y_n))来描述H村的形状,这里(x_1 < x_2 < …< x_n)。瞭望塔可以建造在([x_1,x_n])间的任意位置,但必须满足从瞭望塔的顶端可以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长希望建造的塔高度尽可能小。

    请你写一个程序,帮助dadzhi村长计算塔的最小高度。

    输入

    第一行包含一个整数(n),表示轮廓折线的节点数目。接下来第一行(n)个整数, 为(x_1sim x_n). 第三行n个整数,为(y_1sim y_n)

    输出

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

    样例

    样例输入

    6
    1 2 4 5 6 7
    1 2 2 4 2 1
    

    样例输出

    1.000
    

    数据范围

    对于(60\%)的数据,(Nleq60)
    对于(100\%)的数据,(Nleq300),输入坐标绝对值不超过(10^6),注意考虑实数误差带来的问题。

    题解

    半平面交好题(其实可以暴枚)。

    首先,假设瞭望塔顶为点(P),那么(P)必定在轮廓线上每条边往上的半平面的交集里面。
    因此先做一遍半平面交,由于必定是无界的,我在左右和上侧各加了一个半平面(做完之后把不需要的边界去掉)。
    这样我们就得到了一个下凸壳,如果瞭望塔建在(x_0)这个位置,那么必定是建到直线(x=x_0)与这个凸壳的交点的高度即可。然后考虑到高度是由上下共同决定的,经过显而易见的贪心,可以发现瞭望塔的横坐标要么是这个凸壳上的顶点,要么是下方轮廓线的端点,(O(n))扫一遍即可。总复杂度(O(nlog n))

    坑:答案可能很大,所以(ans)初始值得设得很大。

    (Code:)

    #include <cmath>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define N 100005
    #define eps 1e-8
    int n, m, h, t, cnt;
    bool More(double a, double b){return a > b + eps;}
    bool Less(double a, double b){return a < b - eps;}
    bool Emore(double a, double b){return a > b - eps;}
    bool Eless(double a, double b){return a < b + eps;}
    bool Equal(double a, double b){return fabs(a - b) < eps;}
    struct Point
    {
    	double x, y;
    	Point(){}
    	Point(double a, double b){x = a, y = b;}
    	Point operator + (Point b){return Point(x + b.x, y + b.y);}
    	Point operator - (Point b){return Point(x - b.x, y - b.y);}
    	Point operator * (double c){return Point(x * c, y * c);}
    	Point operator / (double c){return Point(x / c, y / c);}
    }A[N], B[N], p[N];
    struct Line//直线、线段、射线s->t,向量为t-s
    {
    	Point s, t;
    	Line(){};
    	Line(Point a, Point b){s = a, t = b;}
    }S[N], q[N];
    double Cross(Point a, Point b){return a.x * b.y - a.y * b.x;}
    double Length(Point a){return sqrt(a.x * a.x + a.y * a.y);}
    bool Onright(Line s, Point p){return More(Cross(p - s.s, s.t - s.s), 0);}
    Point Intersect(Line a, Line b)
    {
    	double s1 = Cross(a.t - a.s, b.s - a.s);
    	double s2 = Cross(b.t - a.t, a.t - a.s);
    	return b.s + (b.t - b.s) / (s1 + s2) * s1;
    }
    double Angle(Point p){return atan2(p.y, p.x);}
    int cmp(Line s1, Line s2)//象限角度数越低的越靠前(-180,180]
    {
    	Point a = s1.t - s1.s;
    	Point b = s2.t - s2.s;
    	if (!Equal(Angle(a), Angle(b)))return Angle(a) < Angle(b);
    	return Onright(s1, s2.s);
    }
    int cmp2(Point p1, Point p2){return p1.x < p2.x;}
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++)
    		scanf("%lf", &A[i].x);
    	for (int i = 1; i <= n; i++)
    		scanf("%lf", &A[i].y);
    	for (int i = 1; i < n; i++)
    		S[++cnt] = Line(A[i], A[i + 1]);
    	S[++cnt] = Line(Point(A[1].x, 1e+12), Point(A[1].x, A[1].y));
    	S[++cnt] = Line(Point(A[n].x, 1e+12), Point(A[1].x, 1e+12));
    	S[++cnt] = Line(Point(A[n].x, A[n].y), Point(A[n].x, 1e+12));
    	sort(S + 1, S + cnt + 1, cmp);
    	int w = 1;
    	for (int i = 2; i <= cnt; i++)
    		if (!Equal(Angle(S[i].t - S[i].s), Angle(S[i - 1].t - S[i - 1].s)))
    			S[++w] = S[i];
    	cnt = w;
    	h = 1, t = 0;
    	q[++t] = S[1];
    	for (int i = 2; i <= cnt; i++)
    	{
    		while (h < t && Onright(S[i], p[t - 1]))t--;
    		while (h < t && Onright(S[i], p[h]))h++;
    		q[++t] = S[i];
    		if (h < t)
    			p[t - 1] = Intersect(q[t], q[t - 1]);
    	}
    	while (h < t && Onright(q[h], p[t - 1]))t--;
    	if (h < t)p[t] = Intersect(q[t], q[h]);
    	cnt = 0;
    	for (int i = h; i <= t; i++)
    		B[++cnt] = p[i];
    	sort(B + 1, B + cnt + 1, cmp2);
    	w = 1;
    	for (int i = 2; i <= cnt; i++)
    		if (Less(B[i].y, 1e+11))
    			B[++w] = B[i];
    	cnt = w;
    	double ans = 1e+10;
    	int w1 = 1, w2 = 2;
    	A[0].x = A[1].x - 1;
    	B[0].x = B[1].x - 1;
    	while (w1 <= cnt || w2 <= n)
    	{
    		if (w2 > n || (w1 <= cnt && B[w1].x < A[w2].x))
    		{
    			Point s = A[w2 - 1] + (A[w2] - A[w2 - 1]) / (A[w2].x - A[w2 - 1].x) * (B[w1].x - A[w2 - 1].x);
    			ans = min(ans, B[w1].y - s.y);
    			w1++;
    		}
    		else
    		{
    			Point s = B[w1 - 1] + (B[w1] - B[w1 - 1]) / (B[w1].x - B[w1 - 1].x) * (A[w2].x - B[w1 - 1].x);
    			ans = min(ans, s.y - A[w2].y);
    			w2++;
    		}
    	}
    	printf("%.3f
    ", ans);
    }
    
  • 相关阅读:
    mysql 创建++删除 数据表
    mac 配置apache
    mac 安装mysql
    mysql 创建++删除 数据库
    配置默认编码为utf8
    mysql 添加用户
    mysql 查看库结构---查看表结构
    centos7
    centOS 7 安装mysql
    修改字符集
  • 原文地址:https://www.cnblogs.com/ModestStarlight/p/10627778.html
Copyright © 2011-2022 走看看