【BZOJ 1038】 [ZJOI2008]瞭望塔

1038: [ZJOI2008]瞭望塔

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 973  Solved: 428

[Submit][Status]

Description

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

Input

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

Output

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

Sample Input

【输入样例一】

6

1 2 4 5 6 7

1 2 2 4 2 1

【输入样例二】

4

10 20 49 59

0 10 10 0

Sample Output

【输出样例一】

1.000

【输出样例二】

14.500

HINT

对于100%的数据, N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。

半平面交。(感觉很像数学里的线性规划中的可行域)

i到i+1能被看到的点是他们连线的上方区域,对于每一个i和i+1都作出这样的线,最终所有点都能看到的区域就得出了,瞭望塔的塔顶一定在这个区域中。

易证明最优解只可能是已知点上方,或者是可行域顶点处。

简单说一下半平面交的求法:

1.按照极角排序,极角相同按照与y轴交点排序

2.对于极角相同的线只保留一条

3.按顺序扫描每一条线,根据交点的横坐标来剔除肯定没必要的线

4.剩余的就是组成半平面交的轮廓线

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#define M 305
#define eps 1e-9
using namespace std;
struct Point
{
	double x,y;
}a[M];
struct Line
{
	Point A,B;
	double k,b;
	void Getkb()
	{
		k=(A.y-B.y)/(A.x-B.x);
		b=A.y-k*A.x;
	}
}l[M],s[M];
int n,r;
double ans;
bool cmp(Line a,Line b)
{
	if (fabs(a.k-b.k)<eps) return a.b<b.b;
	return a.k<b.k;
}
double Getjiao(Line a,Line b)
{
	return (b.b-a.b)/(a.k-b.k);
}
double bp(double x)   //半平面交
{
	double ans=0.0;
	for (int i=1;i<=r;i++)
		ans=max(ans,s[i].k*x+s[i].b);
	return ans;
}
double yz(double x)   //已知点
{
	int i;
	for (i=1;i<=n;i++)
		if (i==n||a[i+1].x>=x)
			break;
	if (i==n) return -(1e10);
	Line now;
	now.A=a[i],now.B=a[i+1],now.Getkb();
	return now.k*x+now.b;
}
void Getans()
{
	ans=1e10;
	for (int i=1;i<=n;i++)
		ans=min(ans,bp(a[i].x)-a[i].y);
	for (int i=1;i<r;i++)
	{
		Point p;
		p.x=Getjiao(s[i],s[i+1]);
		p.y=s[i].k*p.x+s[i].b;
		ans=min(ans,p.y-yz(p.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++)
		l[i].A=a[i],l[i].B=a[i+1],l[i].Getkb();
	sort(l+1,l+n,cmp);
	r=0;
	for (int i=1;i<n;i++)
		if (i==n-1||fabs(l[i].k-l[i+1].k)>eps)
		{
			while (r>=2&&Getjiao(l[i],s[r])<Getjiao(s[r],s[r-1]))
				r--;
			s[++r]=l[i];
		}
	Getans();
	printf("%.3lf\n",ans);
	return 0;
}

时间: 2024-10-10 10:22:05

【BZOJ 1038】 [ZJOI2008]瞭望塔的相关文章

BZOJ 1038 ZJOI2008 瞭望塔 模拟退火+二分答案

题目大意:给定一条折线,要求选择一个点建立高度为h的瞭望塔,要求瞭望塔塔顶可以看到折线上的每一个点,求h的最小值 正解:半平面交 不会! 于是我们选择模拟退火来寻找瞭望塔的横坐标 确定瞭望塔的高度的时候我们选择二分处理 对于二分的每一个值 我们把折线上的端点从左到右枚举 瞭望塔的塔尖到每个端点的连线必须从左到右逆时针顺序 否则就会被遮挡 如图,塔尖到点2的连线在到点1的连线的顺时针方向,故点1被遮挡,该高度不可行 写完交上去各种秒WA,最后发现我的INF又不够大...我沙茶,我蒟蒻,我这个不长记

BZOJ 1038 ZJOI2008 瞭望塔 半平面交

题目大意及模拟退火题解:见 http://blog.csdn.net/popoqqq/article/details/39340759 这次用半平面交写了一遍--求出半平面交之后.枚举原图和半平面交的每一个点,求出答案就可以 #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 310 #define

1038: [ZJOI2008]瞭望塔

半平面交. 半平面指的就是一条直线的左面(也不知道对不对) 半平面交就是指很多半平面的公共部分. 这道题的解一定在各条直线的半平面交中. 而且瞭望塔只可能在各个点或者半平面交折线的拐点处. 求出半平面交,枚举即可. #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define eps 1e-7 using namespace std; const int maxn

【BZOJ】1038: [ZJOI2008]瞭望塔

http://www.lydsy.com/JudgeOnline/problem.php?id=1038 题意:给出n个x轴各不相同的整点且升序,n<=300,求这些点依次连接后折线的上面取一个点(x, y)使得:x0<=x<=xn,且这个点可以看得到所有线段的所有点.要求这些点到(垂直到)折线的y值之差最小. #include <cstdio> #include <cstring> #include <cmath> #include <stri

bzoj千题计划126:bzoj1038: [ZJOI2008]瞭望塔

http://www.lydsy.com/JudgeOnline/problem.php?id=1038 本题可以使用三分法 将点按横坐标排好序后 对于任意相邻两个点连成的线段,瞭望塔的高度 是单峰函数,而且是下凸函数 感性理解单峰就是 瞭望塔建的靠左,为了能看到右边的,要高一点 瞭望塔建的靠右,为了能看到左边的,要高一点 所以 枚举所有线段,三分线段上建造瞭望塔的位置,所有线段上的瞭望塔高度取最小 #include<cmath> #include<cstdio> #include

【BZOJ1038】[ZJOI2008]瞭望塔 半平面交

[BZOJ1038][ZJOI2008]瞭望塔 Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn.瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置.可见在不同的位置建造瞭望塔,所需要建造的

[ZJOI2008]瞭望塔

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

P2600 [ZJOI2008]瞭望塔

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

【半平面交】bzoj1038 [ZJOI2008]瞭望塔

http://m.blog.csdn.net/blog/qpswwww/44105605 #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define EPS 0.0000001 #define N 311 typedef double db; const db PI=acos(-1.0); struct Point{db x,y;}; typedef Point Ve