• 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
  • 相关阅读:
    2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛
    2020: [Usaco2010 Jan]Buying Feed, II
    3396: [Usaco2009 Jan]Total flow 水流
    3403: [Usaco2009 Open]Cow Line 直线上的牛
    2102: [Usaco2010 Dec]The Trough Game
    最小生成树——Kruskal算法
    最短路径——Floyd算法(含证明)
    最短路径——Bellman-Ford算法以及SPFA算法
    最短路径——Dijkstra算法以及二叉堆优化(含证明)
    普通并查集
  • 原文地址:https://www.cnblogs.com/shutdown113/p/9381140.html
Copyright © 2020-2023  润新知