poj_3168 平面扫描

题目大意

    给定平面上N个矩形的位置(给出矩形的左下角和右上角的坐标),这些矩形有些会有重叠,且重叠只会出现矩形的边重合全部或部分,矩形的顶点重合,而不会出现一个矩形的顶点位于另一个矩形的内部。 
    求出所有不重叠的矩形的个数。

题目分析

    将每个矩形分成4个点,记录每个点所属的矩形id,对4*N个点进行按照x坐标和y坐标排序。 
    然后,沿着x方向进行扫描,对于相同的x,沿着该x坐标,从下向上找那些x坐标等于x的点的y坐标,判断该点所在矩形是否出现重合。若重合,则将该点所属的矩形记为重叠。 
    然后,沿着y方向进行扫描,对于相同的y,沿着该y坐标,从左到右找那些y坐标等于y的点的x坐标,判断该点所在矩形是否出现重合。若重合,则记其所在矩形为重叠。 
    怎么判断沿着某一x坐标或y坐标的那些点所在矩形是否重合呢?以沿着同一x坐标从下到上的那些点为例,用一个变量share_count表示当前时刻进入了几个矩形,从下到上遍历,若点A为某个矩形的下端点,则share_count加1,表示进入一个矩形,否则若A为某个矩形的上端点,share_count减1,表示从一个矩形离开。根据share_count >= 2,可知有矩形重叠,其他情况类似分析,画图可以很容易看出。

    最后,遍历一遍所有的矩形,记下没有重叠的矩形个数即可。

实现(c++)

#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAX_N 200000

struct Point{
	int pos_x;	//x坐标
	int pos_y;	//y坐标
	int rect_id;	//矩形的id
	bool start_x;	//x方向是否是扫描时的入点
	bool start_y;	//方向是否是扫描时的入点
	Point(int p1=0, int p2=0, int id=0, bool sx=0, bool sy = 0) :
		pos_x(p1), pos_y(p2), rect_id(id), start_x(sx), start_y(sy){};
};
Point gPoint[4*MAX_N];

//按照x坐标排序比较函数,用于将 gSortOrder 排序,排序后的gSortOrder 为按照x从小到大排序的 gPoint的索引
bool Cmp_x(int p1, int p2){
	if (gPoint[p1].pos_x == gPoint[p2].pos_x)
		return gPoint[p1].pos_y < gPoint[p2].pos_y;
	return gPoint[p1].pos_x < gPoint[p2].pos_x;
}
//类似 Cmp_x
bool Cmp_y(int p1, int p2){
	if (gPoint[p1].pos_y == gPoint[p2].pos_y)
		return gPoint[p1].pos_x < gPoint[p2].pos_x;
	return gPoint[p1].pos_y < gPoint[p2].pos_y;
}
//排序后的gPoint索引。 按照x或者y坐标将 gPoint 排序后,gPoint中的点的位置。
int gSortOrder[4*MAX_N];
//判断矩形是否有重叠
bool gOverlap[MAX_N];
int main(){
	int n, a, b, c, d;
	while (scanf("%d", &n) != EOF){
		
		for (int i = 0; i < n; i++){
			scanf("%d %d %d %d", &a, &b, &c, &d);
			gPoint[4 * i] = Point(a, b, i, true, true);
			gPoint[4 * i + 1] = Point(a, d, i, true, false);
			gPoint[4 * i + 2] = Point(c, b, i, false, true);
			gPoint[4 * i + 3] = Point(c, d, i, false, false);
		}
		//n 变为点的数目
		n *= 4;
		for (int i = 0; i < n; i++){
			gSortOrder[i] = i;  //排序索引
		}

		memset(gOverlap, false, sizeof(gOverlap));

		//按照x坐标排序
		sort(gSortOrder, gSortOrder + n, Cmp_x);

		int i = 0;
		while(i < n){
			int j = i + 1, k = i;
			int share_count = 1;
			while (j < n && gPoint[gSortOrder[j]].pos_x == gPoint[gSortOrder[i]].pos_x){
				if (gPoint[gSortOrder[k]].pos_y == gPoint[gSortOrder[j]].pos_y){ //两条线重合的情形
					gOverlap[gPoint[gSortOrder[j]].rect_id] = true; 
					gOverlap[gPoint[gSortOrder[k]].rect_id] = true;
				}
				if (gPoint[gSortOrder[j]].start_y){
					share_count++;
					if (share_count >= 2){	//说明有重合
						gOverlap[gPoint[gSortOrder[j]].rect_id] = true;
						gOverlap[gPoint[gSortOrder[j-1]].rect_id] = true;
					}
				}
				else{
					share_count--;
				}
				
				k = j++;
			}
			i = j;
		}
		//按照y坐标排序
		sort(gSortOrder, gSortOrder + n, Cmp_y);
		i = 0;
		while (i < n){
			int j = i + 1, k = i;
			int share_count = 1;
			while (j < n && gPoint[gSortOrder[j]].pos_y == gPoint[gSortOrder[i]].pos_y){
				if (gPoint[gSortOrder[k]].pos_x == gPoint[gSortOrder[j]].pos_x){
					gOverlap[gPoint[gSortOrder[j]].rect_id] = true;
					gOverlap[gPoint[gSortOrder[k]].rect_id] = true;
				}
				if (gPoint[gSortOrder[j]].start_x){
					share_count++;
					if (share_count >= 2){
						gOverlap[gPoint[gSortOrder[j]].rect_id] = true;
						gOverlap[gPoint[gSortOrder[j-1]].rect_id] = true;
					}
				}
				else{
					share_count--;
				}

				k = j++;
			}
			i = j;
		}
		int count = 0;

		//注意,这里的 n 变为 矩形的数目
		for (int i = 0; i < n/4; i++){
			if (!gOverlap[i])
				count++;
		}
		printf("%d\n", count);
	}
	return 0;
}

 

posted @ 2015-10-25 22:42  农民伯伯-Coding  阅读(489)  评论(0编辑  收藏  举报