zoukankan      html  css  js  c++  java
  • hdu5033(单调栈)

    Building

    题意:

      x轴上有n栋高为hi的建筑,现在人在x轴上任意一个位置(保证左右一定有建筑,人的位置没有建筑,人的高可以视为0),求人所能看见的最大的天空的角度。如图所示:

      

    分析:

      整体思路就是维护一个相邻建筑顶连线斜率绝对值上升的单调栈,把建筑和人放在一起计算。首先我们考虑,什么情况下,建筑物会被其他的建筑物遮盖。

        1.a建筑比b建筑矮(a在b的左边),当人从b的右边看的时候,肯定是看不到a的,同理,a比b高,人从a左边也看不到b。

        2.如果a,b,c(从左到右)的高度如果成一个凹字型,那么b也是看不到的。

      然后我们就根据这两点来维护单调栈。当遇见人的时候,如果单调栈中建筑与人之间满足上面两点,则单调栈弹出元素,直到找到人左边(右边)所能够看到的最高的建筑,计算出视线与建筑的夹角即可。遇到建筑的时候,则只需要维护单调栈就好了。

      学习资料:大佬博客

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    #define Pi acos(-1.0)
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int maxn=1e5+100;
    
    int n,q,top,tot,T;
    
    double ans[maxn];
    
    struct Node {
        int id;
        double x,h;
        Node()  {}
        Node(int id,double x,double h):id(id),x(x),h(h) {}
        bool operator < (const Node& rhs) const {
            return x<rhs.x;
        }
        Node operator - (const Node& rhs) const {
            return Node(0,abs(x-rhs.x),abs(h-rhs.h));
        }
    };
    //
    Node st[maxn<<1];
    Node node[maxn<<1];
    
    bool cross(Node a,Node b)
    {
        return b.h*a.x<a.h*b.x;
    }
    
    //如果为凹型,则中间的建筑物是看不到的
    bool judge(Node a,Node b,Node c)
    {
        return cross(c-a,c-b);
    }
    
    //注意算的是哪个角
    double angel(Node a,Node b)
    {
        return atan((b.x-a.x)/a.h);
    }
    
    void solve()
    {
        top=0;
        for(int i=1;i<=tot;i++){
            //如果是建筑物
            if(node[i].id==0){
                //去掉比当前矮的
                while(top&&st[top].h<=node[i].h)    top--;
                //去掉凹处
                while(top>=2&&judge(st[top-1],st[top],node[i]))    top--;
                st[++top]=node[i];
            }
            //如果是人
            else{
                while(top>=2&&judge(st[top-1],st[top],node[i]))    top--;
                ans[node[i].id]+=angel(st[top],node[i]);
            }
        }
    }
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        scanf("%d",&T);
        for(int kase=1;kase<=T;kase++){
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                node[i].id=0;
                scanf("%lf%lf",&node[i].x,&node[i].h);
            }
            tot=n;
            scanf("%d",&q);
            for(int i=1;i<=q;i++){
                tot++;
                node[tot].h=0;
                node[tot].id=i;
                scanf("%lf",&node[tot].x);
            }
    
            cls(ans);
            //计算左边的角度
            sort(node+1,node+tot+1);
            solve();
            //翻转,计算右边的角度
            reverse(node+1,node+tot+1);
            //最大的x变最小的x
            for(int i=1;i<=tot;i++) node[i].x=1e7-node[i].x;
            solve();
    
            printf("Case #%d:
    ",kase);
            for(int i=1;i<=q;i++){
                printf("%.10lf
    ",ans[i]*180/Pi);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    HDU 3911 Black And White 分段树 题解
    Haskell 差点儿无痛苦上手指南
    CFileDialog的使用方法简单介绍
    对 dpif_class 结构体的一点认识
    三层架构之基础知识
    五类常见算法小记 (递归与分治,动态规划,贪心,回溯,分支界限法)
    AlertDialog具体解释
    delphi tcp/ip IdTCPServer1实例一
    23种设计模式(15):备忘录模式
    Android APK反编译具体解释(附图)
  • 原文地址:https://www.cnblogs.com/shutdown113/p/9381140.html
Copyright © 2011-2022 走看看