标签:bzoj oi 计算几何 半平面交
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;
}
![技术分享](http://img.blog.csdn.net/20150225112911693)
【BZOJ 1038】 [ZJOI2008]瞭望塔
标签:bzoj oi 计算几何 半平面交
原文地址:http://blog.csdn.net/regina8023/article/details/43935773