zoukankan      html  css  js  c++  java
  • 2995 楼房

    2995 楼房

     

     时间限制: 1 s
     空间限制: 256000 KB
     题目等级 : 黄金 Gold
     
     
    题目描述 Description

    地平线(x轴)上有n个矩(lou)形(fang),用三个整数h[i],l[i],r[i]来表示第i个矩形:矩形左下角为(l[i],0),右上角为(r[i],h[i])。地平线高度为0。在轮廓线长度最小的前提下,从左到右输出轮廓线。

    输入描述 Input Description

    第一行一个整数n,表示矩形个数

    以下n行,每行3个整数h[i],l[i],r[i]表示第i个矩形。

    输出描述 Output Description

    第一行一个整数m,表示节点个数

    以下m行,每行一个坐标表示轮廓线上的节点。从左到右遍历轮廓线并顺序输出节点。第一个和最后一个节点的y坐标必然为0。

    样例输入 Sample Input

    【样例输入】

    2
    3 0 2
    4 1 3

    【样例输入2】

    5
    3 -3 0
    2 -1 1
    4 2 4
    2 3 7
    3 6 8

    样例输出 Sample Output

    【样例输出】

    6
    0 0
    0 3
    1 3
    1 4
    3 4
    3 0

    【样例输出2】

    14
    -3 0
    -3 3
    0 3
    0 2
    1 2
    1 0
    2 0
    2 4
    4 4
    4 2
    6 2
    6 3
    8 3
    8 0

    数据范围及提示 Data Size & Hint

    对于30%的数据,n<=100

    对于另外30%的数据,n<=100000,1<=h[i],l[i],r[i]<=1000

    对于100%的数据,1<=n<=100000,1<=h[i]<=10^9,-10^9<=l[i]<r[i]<=10^9

    分类标签 Tags 点此展开 

     

    全WA代码:

    //当时想的时候只是想到了两个矩形的重叠、覆盖有无交点的问题
    //当时还庆幸自己写的一定不会越界(毕竟考虑了负数的问题)
    //以后一定要对拍~~
     
    //却 没考虑三个及以上的重叠、交叉、大的完全包含小的,多个交点如何选取等问题 
    
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define N 101000
    struct node{
        int x1,y1,x2,y2;
    }q[N];
    int p,n,h[N],l[N],r[N];
    struct ss{
        int x,y;
    }ans[N];
    bool next=0;
    inline bool cmp(const node &x,const node &y){
        return x.x1<y.x1;
    }
    inline int read(){
        register int x=0,f=1;
        register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++) h[i]=read(),l[i]=read(),r[i]=read();
        for(int i=1;i<=n;i++) q[i].x1=l[i],q[i].x2=r[i],q[i].y1=h[i],q[i].y2=0;
        stable_sort(q+1,q+n+1,cmp);
        ans[++p]=(ss){q[1].x1,q[1].y2};ans[++p]=(ss){q[1].x1,q[1].y1};
        for(int i=1;i<n;i++){
            if(next){
                ans[++p]=(ss){q[i].x1,q[i].y2};ans[++p]=(ss){q[i].x1,q[i].y1};
                next=0;
            }
            if(q[i+1].x1<=q[i].x2){
                if(q[i+1].y1>q[i].y1){
                    if(q[i+1].y1==ans[p].y) ans[++p]=(ss){q[i+1].x1,q[i+1].y1},ans[++p]=(ss){q[i+1].x1,q[i].y1};
                    else ans[++p]=(ss){q[i+1].x1,q[i].y1},ans[++p]=(ss){q[i+1].x1,q[i+1].y1};
                    continue;
                } 
                if(q[i+1].y1<q[i].y1){
                    if(q[i].y1==ans[p].y) ans[++p]=(ss){q[i].x2,q[i].y1},ans[++p]=(ss){q[i].x2,q[i+1].y1};
                    else ans[++p]=(ss){q[i].x2,q[i+1].y1},ans[++p]=(ss){q[i].x2,q[i].y1};
                } 
            }
            else ans[++p]=(ss){q[i].x2,q[i].y1},ans[++p]=(ss){q[i].x2,q[i].y2},next=1;
        }
        ans[++p]=(ss){q[n].x2,q[n].y1};ans[++p]=(ss){q[n].x2,q[n].y2};
        printf("%d
    ",p);
        for(int i=1;i<=p;i++) printf("%d %d
    ",ans[i].x,ans[i].y);
        return 0;
    }

    附上第一个点的数据,希望对你有帮助

    输入数据 (显示前20行)

    10
    728585422 -975253598 -151882490
    374575876 -254784146 181181594
    833835437 47288945 148848803
    759458501 -436030326 231976018
    728539762 -955496022 185702254
    638227308 217298309 704986111
    510564969 -494836052 761895956
    615469816 -832995214 535449271
    272606304 -614433803 -467384146
    557024592 287991704 679834400
    正确答案

    14
    -975253598 0
    -975253598 728585422
    -436030326 728585422
    -436030326 759458501
    47288945 759458501
    47288945 833835437
    148848803 833835437
    148848803 759458501
    231976018 759458501
    231976018 638227308
    704986111 638227308
    704986111 510564969
    761895956 510564969
    761895956 0

    自己离散化画一下图,可能就知道为什么了。

    这是做的第一个扫描线的题目,详细整理一下,留作纪念。

    正解:

    扫描线+堆排序(显然不是题解的代码,没那么无聊抄代码玩)

    AC代码:

    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define N 100100
    struct ss{
        int h,l,r;
        bool operator < (const ss &a) const{
            if(l==a.l) return h>a.h;//双关键字排序 
            return l<a.l;
        }
    }e[N<<1];
    struct node{
        int h,r;
        node(ss x){h=x.h,r=x.r;}
        bool operator < (const node &a) const{
            return h<a.h;
        }
    };
    int n,cnt;//记录点的个数
    pair<int,int>ans[N<<2];//记录答案点的坐标
    priority_queue<node>que;//大根堆 
    ss bfs(ss now,int x){//更新now,处理记录扫描后的矩形的右端点 
        while(!que.empty()){
            node nown=que.top();que.pop();
            if(nown.r>now.r){//有比它宽的,且比它矮的 
                if(nown.h!=now.h) ans[++cnt]=make_pair(now.r,now.h),ans[++cnt]=make_pair(now.r,nown.h);
                now.r=nown.r;now.h=nown.h;
            }
            if(now.r>=x) return now;//*
        }
        //队列空说明:有断层
        ans[++cnt]=make_pair(now.r,now.h),ans[++cnt]=make_pair(now.r,0);//断层左边的两个点 
        now.h=0;now.r=0x7fffffff;//now.h清零,now.r=inf为的是覆盖全区间,在*处起作用 
        return now;
    }
    void solve(){
        ans[++cnt]=make_pair(e[1].l,0);ans[++cnt]=make_pair(e[1].l,e[1].h);//记录左边界答案 
        ss now=e[1];
        for(int i=2;i<=n;i++){//总共分 ①②③ 三大情况,前两种比较直观,第三种比较难处理 
            if(now.h>=e[i].h&&now.r>=e[i].l) que.push(e[i]);//① 存入堆,做备用最高点(这里处理了包含的情况)  
            if(now.h<e[i].h&&now.r>=e[i].l){//
                que.push(now);//把比当前最高点低的点都存入堆,一个也不能漏 
                ans[++cnt]=make_pair(e[i].l,now.h);//较低点
                now=e[i];
                ans[++cnt]=make_pair(e[i].l,now.h);//较高点 
            }
            if(now.r<e[i].l){//
                now=bfs(now,e[i].l);//判断一个矩形横穿e[i]这个矩形 
                if(now.h>=e[i].h&&now.r>=e[i].l) que.push(e[i]);
                if(now.h<e[i].h&&now.r>=e[i].l){//断层和比他低的一起处理 
                    que.push(now);//上边的now=bfs..和这里很好的处理了输出点坐标的顺序问题 
                    ans[++cnt]=make_pair(e[i].l,now.h);
                    now=e[i];
                    ans[++cnt]=make_pair(e[i].l,now.h);    
                }
            } 
        }
        bfs(now,0x7fffffff);//遍历全区间做收尾工作:因为最后一个点的右边界不一定是所有元素的最右边界 
        //总结:只要最高点发生跃迁,就要记录答案 
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d%d",&e[i].h,&e[i].l,&e[i].r);
        sort(e+1,e+n+1);//左端点升序排列 
        solve();
        printf("%d
    ",cnt);
        for(int i=1;i<=cnt;i++) printf("%d %d
    ",ans[i].first,ans[i].second);//因为记录是按顺序记录的,所以按顺序输出即可 
        return 0;
    } 
  • 相关阅读:
    C# 6.0 新特征 Demo
    SmartGit 试用过期
    .net版Git Server --- bonobo
    线程操作若干(复习)
    异步的两种写法: async 与 BeginInvoke
    winform 防止主界面卡死
    wcf 出现 IsContentTypeSupported 错误
    NodeJs 实时压缩 项目js文件
    Excel 公式(细节若干)
    itextSharp 对pdf的每个页面添加footer/header
  • 原文地址:https://www.cnblogs.com/shenben/p/5732940.html
Copyright © 2011-2022 走看看