poj 3168 Barn Expansion

Barn Expansion
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 2465 Accepted: 666

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块矩阵,如果其中某块矩阵与其他任意一块矩阵有接触的话(边或者顶点有接触),那么这块矩阵就无法扩充,问到底有多少矩阵是可以扩充的。
思路:分别用平行于y轴和x轴方向的直线扫描平面。具体做法,现在不妨用平行于y轴的直线来扫描平面,扫描到如下情况时,我们首先给所有顶点编号,不妨从下往上编,这样就得从下往上考虑,如果当前考虑到的顶点是一个矩阵一条边的起始点,那么记录器num++,
遇到的顶点是一条边的终点,num--,表示这条边不会再和接下来的矩阵存在重叠的关系。如果遇到了某个起始点,num++后num的值大于等于2,说明这个顶点左右两边的矩阵一定是有接触的(意味着一条边还没走到终点又碰到了一个起始点,那么这两条边就就有一部分重叠在了一起),例如图中,先碰到了顶点1,后来又碰到了顶点2,那么之后那部分的边就是左右矩阵所公用的。那么遇到一个终点,num--后num==0,说明这个终点之后的顶点就不能和之前的矩阵有公共边的关系了。

 

AC代码:

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int N_MAX =25000+ 5;
int N;

enum point_type{
    START, END
};
struct P {
    int x, y;
    int id;//坐标点是属于第几个矩形的
    point_type type;
    P(int x,int y,int id,point_type type):x(x),y(y),id(id),type(type) {}
    bool operator <(const P&b)const {
        if (x != b.x)return x < b.x;
        else if (y != b.y)return y < b.y;
        else return type < b.type;
    }
};
//P p1[N_MAX], p2[N_MAX];
vector<P>p1;
vector<P>p2;
bool ok[N_MAX];
void scan( vector<P>p1) {
     vector<P>::iterator it = p1.begin();
     int connect_num = 0;
     int cur_x = it->x;
     bool illegal = 0;
    while (it!=p1.end()) {
        if (cur_x != it->x) {//扫描到了新的一列上
            connect_num = 0;
            cur_x = it->x;
            illegal = 0;
        }
        int cur_y = it->y;
        while (it!=p1.end()&&cur_x==it->x&&cur_y==it->y) {//处理同一个坐标点或者同一列上的坐标点
            if (illegal)ok[it->id] = true;//这个点重合了
            if (it->type == START) {
                connect_num++;
                if (connect_num >= 2)illegal = true;//按y坐标向上扫描扫描到某个顶点开始有边或者点重合了,那么两边的矩阵都不能扩展了
            }
            if (it->type == END) {
                connect_num--;
                if (connect_num == 0)illegal = false;
            }
            it++;
        }
        
    }
}
void clear() {
    p1.clear();
    p2.clear();
}
int main() {
    while (scanf("%d",&N)!=EOF) {
        for (int i = 0;i<N;i++) {
           int A,B,C,D;
           scanf("%d%d%d%d",&A,&B,&C,&D);
           p1.push_back(P(A, B, i, START));
           p1.push_back(P(C, B, i, START));
           p1.push_back(P(A,D,i,END));
           p1.push_back(P(C, D, i, END));
           p2.push_back(P(B,A,i,START));
           p2.push_back(P(D,A,i,START));
           p2.push_back(P(B,C,i,END));
           p2.push_back(P(D, C, i, END));
        }
        sort(p1.begin(), p1.end());
        sort(p2.begin(),p2.end());
        memset(ok, 0, sizeof(ok));
        scan(p1);
        scan(p2);
        printf("%d\n", count(ok, ok + N,false));
        clear();
    }
    return 0;
}

 


 


 


 


 


 

转载于:https://www.cnblogs.com/ZefengYao/p/7360272.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值