zoukankan      html  css  js  c++  java
  • 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
    ", count);
    	}
    	return 0;
    }
    
  • 相关阅读:
    多线程创建方式四种

    归并排序
    Spark调优之--资源调优、并行度调优
    多线程中的上下文切换
    守护线程和本地线程
    线程和进程的区别
    3. 无重复字符的最长子串
    [蓝桥杯][历届试题]连号区间数
    [蓝桥杯][历届试题]蚂蚁感冒
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4909878.html
Copyright © 2011-2022 走看看