POJ1177矩形面积并(矩形切割+括号匹配)

题目:http://poj.org/problem?id=1177

 

分析:(括号匹配)首先把矩形的上边界作为左括号边,下边界作为右括号边,然后上下排序。假定排完序之后是下

面的状态:(())()(()()(()))

 

考虑“最外侧”的括号的数量。显然上面的那个串是(()) & () & (()()(()))

有六个最外侧括号,那么边界数量就是6。排序的复杂度O(nlogn),对于上面的思路,针对横边来说,如果并不是完全包括的

办,那就是将边分割成一些小段在用括号匹配。 括号匹配用到此题恰到好处即在于可以有效处理掉重复覆盖避免重复计算边

问题。因为先将每个矩形的上、下边附一个标号1、-1。而对于此题有一个性质是,无论矩形怎么覆盖,最终对于某一小段边

定会有一个对应的边存在。那么1、-1正好起到匹配的作用。

#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;
const int maxn = 10005;

struct NODE
{
    int cankao,weizhi,st,en; //weizhi为表明匹配边
}nodex[maxn],nodey[maxn];

int mapx[2*maxn],mapy[2*maxn],lenx[maxn],leny[maxn],vist[maxn];

bool cmp(NODE n1,NODE n2)
{
    return n1.cankao<n2.cankao;
}

int main()
{
    int n,i,j,x1,y1,x2,y2;
    memset(mapx,0,sizeof(mapx));
    memset(mapy,0,sizeof(mapy));
    scanf("%d",&n);
    for(i=0; i<n; i++) //存信息
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        x1+=maxn;
        y1+=maxn;
        x2+=maxn;
        y2+=maxn;
        mapx[x1]=mapx[x2]=mapy[y1]=mapy[y2]=1;
        nodex[2*i].cankao=y1;
        nodex[2*i].weizhi=1;
        nodex[2*i].st=x1;
        nodex[2*i].en=x2;
        nodex[2*i+1].cankao=y2;
        nodex[2*i+1].weizhi=-1;
        nodex[2*i+1].st=x1;
        nodex[2*i+1].en=x2;
        nodey[2*i].cankao=x1;
        nodey[2*i].weizhi=1;
        nodey[2*i].st=y1;
        nodey[2*i].en=y2;
        nodey[2*i+1].cankao=x2;
        nodey[2*i+1].weizhi=-1;
        nodey[2*i+1].st=y1;
        nodey[2*i+1].en=y2;
    }
    stable_sort(nodex,nodex+2*n,cmp);
    stable_sort(nodey,nodey+2*n,cmp);
    int tmpx=0,tmpy=0,ans=0;
    for(i=0; i<2*maxn; i++)
    {
        if(mapx[i])
        {
            mapx[i]=tmpx;
            lenx[tmpx++]=i;
        }
        if(mapy[i])
        {
            mapy[i]=tmpy;
            leny[tmpy++]=i;
        }
    }
    for(i=0; i<2*n; i++) //离散化
    {
        nodex[i].st=mapx[nodex[i].st];
        nodex[i].en=mapx[nodex[i].en];
        nodey[i].st=mapy[nodey[i].st];
        nodey[i].en=mapy[nodey[i].en];
    }
    memset(vist,0,sizeof(vist));
    for(i=0; i<2*n; i++)
    {
        for(j=nodex[i].st; j<nodex[i].en; j++)
        {
            vist[j]+=nodex[i].weizhi;
            if(vist[j]==0) //匹配成功
                ans+=lenx[j+1]-lenx[j];
        }
    }
    memset(vist,0,sizeof(vist));
    for(i=0; i<2*n; i++)
    {
        for(j=nodey[i].st; j<nodey[i].en; j++)
        {
            vist[j]+=nodey[i].weizhi;
            if(vist[j]==0)
                ans+=leny[j+1]-leny[j];
        }
    }
    printf("%d\n",2*ans);
    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值