1. 程式人生 > >POJ1151 Atlantis 【掃描線】

POJ1151 Atlantis 【掃描線】

truct 做到 距離 clu string date 切割 top each

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


POJ1151 Atlantis 【掃描線】