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\nTotal explored area: %.2lf\n\n", 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\nTotal explored area: %.2lf\n\n", cas++, sum);
	}
	return 0;
}
时间: 2024-10-11 06:45:29

POJ1151 Atlantis 【扫描线】的相关文章

poj1151 Atlantis——扫描线+线段树

题目:http://poj.org/problem?id=1151 经典的扫描线问题: 可以用线段树的每个点代表横向被矩形上下边分割开的每一格,这样将一个矩形的出现或消失化为线段树上的单点修改: 每个格子记录两个值:c(矩形存在情况),sum(对当前答案作出贡献的长度): 将y离散化作为建树的依据: 一开始没想到线段树上的点应该是横向的格子,写了个乱七八糟: #include<iostream> #include<cstdio> #include<cstring> #i

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

POJ 1151 Atlantis 扫描线+线段树

点击打开链接 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17252   Accepted: 6567 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of pa

ACM学习历程—POJ1151 Atlantis(扫描线 &amp;&amp; 线段树)

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

POJ 1151 HDU 1542 Atlantis(扫描线)

题目大意就是:去一个地方探险,然后给你一些地图描写叙述这个地方,每一个描写叙述是一个矩形的右下角和左上角.地图有些地方是重叠的.所以让你求出被描写叙述的地方的总面积. 扫描线的第一道题,想了又想,啸爷还给我讲了讲,最终有点理解了啊. 先说扫描线:书上说扫描线不是一个物体.而是一个概念. 在计算几何中的作用类似于图论中的bfs与dfs.所以还是须要多做题目来体会一下啊. 这道题目的做法是:离散化x坐标.然后依照y坐标的大小进行排序,每一条保存它的左边界的位置与右边界的位置.以及自身的高度. 还有就

poj1151 Atlantis

                                                                      Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19585   Accepted: 7436 Description There are several ancient Greek texts that contain descriptions of the fabl

POJ 1151 Atlantis(扫描线)

题目原链接:http://poj.org/problem?id=1151 题目中文翻译: POJ 1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25769   Accepted: 9477 Description 有几个古希腊文本包含传说中的亚特兰蒂斯岛的描述. 其中一些文本甚至包括岛屿部分地图. 但不幸的是,这些地图描述了亚特兰蒂斯的不同区域. 您的朋友Bill必须知道地图的总面积. 你(不

poj1151(扫描线)

4837: Poj1151 Atlantis Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 21  Solved: 12[Submit][Status][Web Board] Description 给定平面直角坐标系中的N个矩形,求它们的面积并,即这些矩形的并集在坐标系中覆盖的总面积,如下图所示. Input Output Sample Input 2 10 10 20 20 15 15 25 25.5 0 Sample Output Test

扫描线

扫描线这个东西比较玄虚,总的来讲大概是一种思想. 想象一条线从区间(或是其他什么)慢慢扫过,线每次碰到某个东西称为事件,然后根据事件来进行一些操作. 一般来讲,区间用扫描线要用到离散化和线段树来优化(要不然). 具体的扫描线怎么用,主要是根据题目来做. 现在来看看扫描线的题目: POJ1151 Atlantis: 给出n个矩形,求面积并. 1.对于矩形(x1,y1)-(x2,y2),添加两个事件:(x1,y1,y2),(x2,y1,y2) 2.从左到右扫描所有事件 3.变成:加入一个区间,删除一