zoukankan      html  css  js  c++  java
  • POJ1151 Atlantis 【扫描线】

    Atlantis
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 16882   Accepted: 6435

    Description

    There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

    Input

    The input consists of several test cases. Each test case starts with a line containing a single integer n (1 <= n <= 100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area. 
    The input file is terminated by a line containing a single 0. Don't process it.

    Output

    For each test case, your program should output one section. The first line of each section must be "Test case #k", where k is the number of the test case (starting with 1). The second one must be "Total explored area: a", where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point. 
    Output a blank line after each test case.

    Sample Input

    2
    10 10 20 20
    15 15 25 25.5
    0

    Sample Output

    Test case #1
    Total explored area: 180.00 

    我累个去~~这题从早上8:30一直做到如今22:50,总算是A掉了,上午一直没看懂扫描线,然后看到傍晚总算是有些头目了,结果写的时候非常生疏,等到摸摸索索完全然全地写完已经大半夜了。满心欢喜地提交又各种RE,開始以为是数组开小了,然后翻了倍依然RE,就这样RE了6、7次后猛地发现是freopen忘了凝视掉,o(╯□╰)o...尼玛啊!!总归是在睡觉前找到问题了。

    题意:给定n个矩形的对角坐标,各自是左下和右上,浮点型。求矩形覆盖的面积。

    题解:扫描线解法,将每一个矩形分别以长宽为直线切割,终于垂直于x轴的割线有2n条,垂直于y轴的割线也有2n条,将这些割线存到两个数组里并排序,建立一个线段树用以维护扫描线当前在y轴方向覆盖的长度。最后,在扫描线从左往右扫描的过程中,一旦经过一条垂直于x轴的割线就立刻将这条割线更新到线段树里,覆盖面积即为两条相邻扫描线的距离乘以左边一条扫描线的长度,累加下去即得终于覆盖面积。x轴割线数组须要记录边是入边还是出边。若是出边则右边的的面积对此出边是不计的,可是存在入边重合的情况,须要详细考虑。

    2014-9-23 23:32:51更新

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #define maxn 202
    #define lson l, mid, rt << 1
    #define rson mid, r, rt << 1 | 1
    using namespace std;
    
    struct Node {
        double y1, y2, len;
        int covers;
    } T[maxn << 2];
    struct Node2 {
        double x, y1, y2;
        int isLeft;
    } xNode[maxn];
    double yNode[maxn];
    
    bool cmp(Node2 a, Node2 b) {
        return a.x < b.x;
    }
    
    void pushUp(int l, int r, int rt) {
        if(T[rt].covers > 0)
            T[rt].len = T[rt].y2 - T[rt].y1;
        else if(r - l == 1) T[rt].len = 0.0;
        else T[rt].len = T[rt << 1].len + T[rt << 1 | 1].len;
    }
    
    void build(int l, int r, int rt) {
        T[rt].covers = 0;
        T[rt].y1 = yNode[l];
        T[rt].y2 = yNode[r];
        T[rt].len = 0.0;
        if(r - l == 1) return;
        int mid = (l + r) >> 1;
        build(lson);
        build(rson);
    }
    
    void update(Node2 x, int l, int r, int rt) {
        if(x.y1 == T[rt].y1 && x.y2 == T[rt].y2) {
            T[rt].covers += x.isLeft;
            pushUp(l, r, rt);
            return;
        }
        int mid = (l + r) >> 1;
        if(x.y2 <= yNode[mid]) update(x, lson);
        else if(x.y1 >= yNode[mid]) update(x, rson);
        else {
            Node2 x1 = x, x2 = x;
            x1.y2 = x2.y1 = yNode[mid];
            update(x1, lson);
            update(x2, rson);
        }
        pushUp(l, r, rt);
    }
    
    int main() {
        //freopen("stdin.txt", "r", stdin);
        int n, i, id, cas = 1;
        double x1, y1, x2, y2, sum;
        while(scanf("%d", &n), n) {
            for(i = id = 0; i < n; ++i) {
                scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
                yNode[id] = y1;
                xNode[id].x = x1;
                xNode[id].y1 = y1;
                xNode[id].y2 = y2;
                xNode[id++].isLeft = 1;
    
                yNode[id] = y2;
                xNode[id].x = x2;
                xNode[id].y1 = y1;
                xNode[id].y2 = y2;
                xNode[id++].isLeft = -1;
            }
            sort(yNode, yNode + id);
            build(0, id - 1, 1);
            sort(xNode, xNode + id, cmp);
            update(xNode[0], 0, id - 1, 1);
            for(i = 1, sum = 0.0; i < id; ++i) {
                sum += T[1].len * (xNode[i].x - xNode[i-1].x);
                update(xNode[i], 0, id - 1, 1);
            }
            printf("Test case #%d
    Total explored area: %.2lf
    
    ", cas++, sum); 
        }
        return 0;
    }


    #include <stdio.h>
    #include <algorithm>
    #define maxn 202
    #define lson l, mid, rt << 1
    #define rson mid, r, rt << 1 | 1
    using std::sort;
    
    struct Node{
    	double y1, y2, height; //y1, y2记录y坐标离散前的值
    	int coverTimes;
    } tree[maxn << 2]; //区间树
    double yArr[maxn]; //垂直于Y轴的割线
    struct node{
    	double x, y1, y2;
    	int isLeftEdge;
    } xArr[maxn]; //垂直于X轴的割线
    
    bool cmp(node a, node b){ return a.x < b.x; }
    
    void build(int l, int r, int rt)
    {
    	tree[rt].coverTimes = 0;
    	tree[rt].height = 0;
    	tree[rt].y1 = yArr[l];
    	tree[rt].y2 = yArr[r];
    	if(r - l == 1) return;
    	
    	int mid = (l + r) >> 1;
    	build(lson);
    	build(rson);
    }
    
    void getSweepLinesHeight(int l, int r, int rt)
    {//因为存在线段覆盖的情况,所以长线段结束并不能代表扫描线长度为0
    	if(tree[rt].coverTimes > 0){ 
    		tree[rt].height = tree[rt].y2 - tree[rt].y1;
    	}else if(r - l == 1){
    		tree[rt].height = 0;
    	}else tree[rt].height = tree[rt << 1].height + tree[rt << 1 | 1].height;
    }
    
    void update(node xNode, int l, int r, int rt)
    {
    	if(xNode.y1 == tree[rt].y1 && xNode.y2 == tree[rt].y2){
    		tree[rt].coverTimes += xNode.isLeftEdge;
    		getSweepLinesHeight(l, r, rt);
    		return;
    	} //include r - l == 1
    	
    	int mid = (l + r) >> 1;	
    	if(xNode.y2 <= yArr[mid]) update(xNode, lson);
    	else if(xNode.y1 >= yArr[mid]) update(xNode, rson);
    	else{
    		node temp = xNode;
    		temp.y2 = yArr[mid];
    		update(temp, lson);
    		temp = xNode; temp.y1 =yArr[mid];
    		update(temp, rson);
    	}
    	
    	getSweepLinesHeight(l, r, rt); //Attention!	
    }
    
    int main()
    {
    	//freopen("stdin.txt", "r", stdin);
    	int n, i, cas = 1, id;
    	double x1, y1, x2, y2, sum;
    	while(scanf("%d", &n), n){
    		for(i = id = 0; i < n; ++i){
    			scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
    			yArr[id] = y1; xArr[id].x = x1;
    			xArr[id].isLeftEdge = 1; //1表示左。-1表示右
    			xArr[id].y1 = y1; xArr[id++].y2 = y2;
    			
    			yArr[id] = y2; xArr[id].x = x2;
    			xArr[id].isLeftEdge = -1;
    			xArr[id].y1 = y1; xArr[id++].y2 = y2;
    		}
    		
    		sort(yArr, yArr + id);
    		sort(xArr, xArr + id, cmp);
    		build(0, id - 1, 1);		
    				
    		update(xArr[0], 0, id - 1, 1);
    		for(i = 1, sum = 0; i < id; ++i){
    			sum += tree[1].height * (xArr[i].x - xArr[i - 1].x);
    			update(xArr[i], 0, id - 1, 1);
    		}
    		
    		printf("Test case #%d
    Total explored area: %.2lf
    
    ", cas++, sum);
    	}
    	return 0;
    }


  • 相关阅读:
    把TXT GB2312文件转换成TXT UTF8文件
    把ANSI格式的TXT文件批量转换成UTF-8文件类型
    GB2312转换成UTF-8与utf_8转换成GB2312
    SQL 字符串处理函数大全
    编写一个程序,建立一个动态数组,为动态数组的元素赋值,显示动态数组的值并删除动态数组--简单
    设计一个使用常量成员函数的示范程序-简单
    声明一个复数类complex,使用友元函数add实现复数的加法-简单
    使用内联函数设计一个类,用来表示直角坐标系中的任意一条直线并输出它的属性
    设计一个点类point,再设计一个矩形类,矩形类使用point类的两个坐标点作为矩形的对角顶点,并可以输出4个坐标值和面积。使用测试程序验证程序。
    利用函数模板设计一人求数组元素总和的函数,并检验之-简单
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6953123.html
Copyright © 2011-2022 走看看