HDU 5033 Building(模拟凸包建立过程)

题目链接:

传送门

题意:

在坐标轴上有n个点,每个点的有一个建筑物,高度为h,求一个人站在坐标为 (x,0) 的位置所能看到的天空的角度。

分析:

我们将询问的点 (x,0) 也插入到给定的点中,然后建立一个模拟建立凸包的过程,凸包上的一个点一定要与它相邻点的斜率一定要大于与它相邻的点 x1 x1 相邻的点 x2 的斜率。因此我们正着求一次凸包得到每个点与左边形成的角度,然后再倒着做一次凸包求出与右边形成的角度即可。

Code

#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5+10;

const double eps = 1e-10;

const double pi = acos(-1.0);

int dcmp(double x) {
    if(fabs(x)<eps) return 0;
    else return x < 0 ? -1 : 1;
}

struct Point {
    double x, y;
    int id;
    double thea1,thea2;
    bool operator < (const Point& a) const {
        return x < a.x;
    }
    bool operator == (const Point B)const {
        return dcmp(x-B.x)==0&&dcmp(y-B.y)==0;
    }
} p[maxn],st[maxn];

double calc(Point a,Point b){
    return (b.y-a.y)/fabs(b.x-a.x);
}

bool cmp(const Point &A,const Point &B){
    return A.id<B.id;
}

int main()
{
    int t,n,m,cas=1;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%lf%lf%",&p[i].x,&p[i].y);
            p[i].id=i;
        }
        scanf("%d",&m);
        for(int i=n;i<n+m;i++){
            scanf("%lf",&p[i].x);
            p[i].id=i;
            p[i].y=0;
        }
        n+=m;
        sort(p,p+n);
        int top=0;
        st[0]=p[0];
        for(int i=1;i<n;i++){
            if(p[i].id<n-m){
                while(top&&calc(p[i],st[top])<calc(st[top],st[top-1])){
                    top--;
                }
                st[++top]=p[i];
            }
            else{
                int tmp = top;
                while(tmp&&calc(p[i],st[tmp])<calc(p[i],st[tmp-1]))
                    tmp--;
                p[i].thea1=calc(p[i],st[tmp]);
            }
        }
        top=0;
        st[0]=p[n-1];
        for(int i=n-2;i>=0;i--){
            if(p[i].id<n-m){
                while(top&&calc(p[i],st[top])<calc(st[top],st[top-1]))
                    top--;
                st[++top]=p[i];
            }
            else{
                int tmp = top;
                while(tmp&&calc(p[i],st[tmp])<calc(p[i],st[tmp-1]))
                    tmp--;
                p[i].thea2=calc(p[i],st[tmp]);
            }
        }
        sort(p,p+n,cmp);
        printf("Case #%d:\n",cas++);
        for(int i=n-m;i<n;i++){
            double thea = pi - atan(p[i].thea1)-atan(p[i].thea2);
            printf("%.5lf%c",thea*180.0/pi,i==n-1 ? '\n' : ' ');
        }
    }
    return 0;
}

你可能感兴趣的:(计算几何-凸包)