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; }