POJ 3168 Barn Expansion (平面扫描)

57 篇文章 0 订阅
Barn Expansion
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 2305 Accepted: 607

Description

Farmer John has N (1 <= N <= 25,000) rectangular barns on his farm, all with sides parallel to the X and Y axes and integer corner coordinates in the range 0..1,000,000. These barns do not overlap although they may share corners and/or sides with other barns.

Since he has extra cows to milk this year, FJ would like to expand some of his barns. A barn has room to expand if it does not share a corner or a wall with any other barn. That is, FJ can expand a barn if all four of its walls can be pushed outward by at least some amount without bumping into another barn. If two barns meet at a corner, neither barn can expand.

Please determine how many barns have room to expand.

Input

Line 1: A single integer, N

Lines 2..N+1: Four space-separated integers A, B, C, and D, describing one barn. The lower-left corner of the barn is at (A,B) and the upper right corner is at (C,D).

Output

Line 1: A single integer that is the number of barns that can be expanded.

Sample Input

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

Sample Output

2

Hint

Explanation of the sample:

There are 5 barns. The first barn has its lower-left corner at (0,2) and its upper-right corner at (2,7), and so on.

Only two barns can be expanded --- the first two listed in the input. All other barns are each in contact with at least one other barn.

大体题意:
给你n个矩形,告诉你矩形的左下角坐标和右上角坐标,求出有多少矩形是完全独立的,就是说不与其他矩形有点或线的接触。
思路:
玩了很久了,才补完这道题目,补完睡觉了= =!
题目中给的矩形都是平行于x轴和y轴的,所以可以直接判断横线和竖线是否接触!
方法是:
先考虑竖线吧(a,b)这个点,定义一个线类,有值key,因为是竖线,x坐标都一样,所以值就是横坐标,
key = a,  y坐标从b到d,所以起点是b,终点是d。 (还需注意一个矩形的四条线的id都是一样的)

这样构造完所有竖线后,给他们排个序,先按值从小排序(方便枚举)相等的话按照起点排序。
然后开始枚举所有竖线,如果下一个线的起点比上一个线的终点小的话,说明有接触了,把这两条线的id 都记为已接触。
注:因为平行线段要接触必须共线了,所以先找值一样的所有线段(不这样做会超时)
以同样的方法构造枚举横线。
最后枚举横线加竖线,把没接触的线加起来即可!
这就是平面扫描
详细见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 25000 + 10;

struct Node {
    int a,b,c,d;
    void read(int aa,int bb,int cc,int dd){
        a = aa; b = bb; c = cc; d = dd;
    }
}p[maxn];
struct Line{
    int key,st,ed;
    int id;
    bool operator < (const Line& rhs) const {
        return key < rhs.key || (key == rhs.key && st < rhs.st);
    }
}l[maxn<<1];
int vis[maxn<<1];
int main(){
    int n;
    scanf("%d",&n);
    for (int i = 0 ; i < n; ++i){
        int a,b,c,d;
        scanf("%d %d %d %d",&a,&b,&c,&d);
        p[i].read(a,b,c,d);
    }
    for (int i = 0; i < n; ++i){
        l[2*i].key = p[i].a;
        l[2*i].st = p[i].b;
        l[2*i].ed = p[i].d;
        l[2*i].id = i;
        l[2*i+1].key = p[i].c;
        l[2*i+1].st = p[i].b;
        l[2*i+1].ed = p[i].d;
        l[2*i+1].id = i;
    }
    sort(l,l+2*n);
    int i,j;
    for (i = 0; i < 2*n; ++i){
        for (j = i; j < 2*n; ++j){
            if (l[j].key != l[i].key)break;
        }
        int up = l[i].ed;
        for (int k =  i+1; k < j; ++k){
            if (l[k].st <= up){
                vis[l[k].id] = vis[l[k-1].id ] = 1;
            }
            up = max(up,l[k].ed);
        }
        i=j-1; // 注意,i不变的话 会超时!!
    }

    for (int i = 0; i < n; ++i){
        l[2*i].key = p[i].b;
        l[2*i].st = p[i].a;
        l[2*i].ed = p[i].c;
        l[2*i].id = i;
        l[2*i+1].key = p[i].d;
        l[2*i+1].st = p[i].a;
        l[2*i+1].ed = p[i].c;
        l[2*i+1].id = i;
    }
    sort(l,l+2*n);
    for (i = 0; i < 2*n; ++i){
        for (j = i; j < 2*n; ++j){
            if (l[j].key != l[i].key)break;
        }
        int up = l[i].ed;
        for (int k =  i+1; k < j; ++k){
            if (l[k].st <= up){
                vis[l[k].id] = vis[l[k-1].id ] = 1;
            }
            up = max(up,l[k].ed);
        }
        i=j-1; // 注意,i不变的话 会超时!!
    }
    int ans = 0;
    for (int i = 0; i < n; ++i){
        if (!vis[i])++ans;
    }
   // ans/=4;
    printf("%d\n",ans);

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值