自由堆叠的屋顶——线段树的应用

来源:互联网 发布:服务器抓鸡软件 编辑:程序博客网 时间:2024/05/01 11:06

自由堆叠的屋顶

时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 109            测试通过 : 39 

比赛描述

sed 同学最近突发奇想,认为伟大的建筑物的屋顶应该是“自由堆叠”出来的,他的设计方案是:将各种颜色的长方形建筑板材堆叠在一起,并保证各个板材长边、宽边均相互平行或在一条直线上,板材之间的重叠部分用连接装置固定在一起。

你的任务是计算这个“自由堆叠的屋顶”所覆盖的面积。sed 将会在屋顶平面上建立一个二维坐标系,提供给你每个长方形建筑板材左上角、右下角的坐标。为简化计算,这里忽略板材的厚度,假设它们都在同一个平面上。



输入

输入数据包含多组测试案例。

每组测试案例由N(0≤N≤100)开头,后续N行每行包含4个实数x1;y1;x2;y2 (0 <= x1 < x2 <= 100000建筑单位;0 <= y1 < y2 <= 100000建筑单位)。

(x1; y1) 、 (x2;y2)分别是长方形建筑板材左上角、右下角的坐标。

单独一个行输入0表示输入结束,无需处理。

输出

对于每个测试用例,输出以下信息: 第1行形如“Build #k”,这里k是测试用例序号(以1开始),第二行形如“Total area: a”,a是总覆盖面积,保留两位小数。

样例输入

2
10 10 20 20
15 15 25 25.5
1
10 10 20 20
0

样例输出

Build #1
Total explored area: 180.00
Build #2
Total explored area: 100.00

题目来源

南京邮电大学计算机学院首届ACM程序设计大赛(2009)


我的答案(Java):(WrongAnswerAtTest1 不知道问题出在哪儿

import java.text.DecimalFormat;import java.util.Arrays;import java.util.Comparator;import java.util.Scanner;public class Main{public final int MAXN=100;public int N;// 板块个数public float[] position=new float[MAXN*4];// 板块坐标public float[] X;// 保存线段的横坐标public Line[] lines;// 保存线段public Node[] segTree=new Node[MAXN*8];public void input(Scanner sc) throws Exception{try {// 根据输入的n来创建数组//int posNum = 4 * N;//position = new float[posNum];for (int i = 0; i < N; i++) {float x1 = sc.nextFloat();float y1 = sc.nextFloat();float x2 = sc.nextFloat();float y2 = sc.nextFloat();if (!checkXY(x1, y1, x2, y2))throw new Exception("坐标不合法");position[i * 4 + 0] = x1;position[i * 4 + 1] = y1;position[i * 4 + 2] = x2;position[i * 4 + 3] = y2;}} catch (Exception e) {throw e;}}/** * 检查坐标是否合法 * @param x1 * @param y1 * @param x2 * @param y2 * @return */public boolean checkXY(float x1,float y1,float x2,float y2 ){if (check(x1) && check(x2) && check(y1) && check(y2) && x1 < x2&& y1 < y2)return true;return false;}private boolean check(float x){if(x<0||x>100000)return false;return true;}/** * 将矩形的横边转化为线段,按照y值排序;同时将横坐标排序去重 * @return */public void transfer(){lines=new Line[N*2];X=new float[N*2];for(int i=0;i<N;i++){float x1=position[i*4+0];float y1=position[i*4+1];float x2=position[i*4+2];float y2=position[i*4+3];Line line1=new Line(x1, x2, y1);line1.seq=1;// 下边Line line2=new Line(x1, x2, y2);line2.seq=-1;// 上边lines[i*2]=line1;lines[i*2+1]=line2;X[i*2]=x1;X[i*2+1]=x2;}}/** * 线段排序 * @param lines */public void sort(Line[] lines,int fromIndex,int toIndex){Arrays.sort(lines,fromIndex,toIndex, new Comparator<Line>() {@Overridepublic int compare(Line o1, Line o2) {float f=o1.y-o2.y;if(f>0)return 1;else if(f<0)return -1;else return 0;}});}public void sort(float[] X,int fromIndex,int toIndex){Arrays.sort(X,fromIndex,toIndex);}public int search(float[] X,int fromIndex,int toIndex,float x){return Arrays.binarySearch(X,fromIndex,toIndex, x);}/** * 构建线段树 * @param nodeIdx * @param leftIdx * @param rightIdx */public void build(int nodeIdx,int leftIdx,int rightIdx){if(segTree[nodeIdx]==null)segTree[nodeIdx]=new Node();segTree[nodeIdx].left=leftIdx;segTree[nodeIdx].right=rightIdx;segTree[nodeIdx].cover=0;// 默认值为0segTree[nodeIdx].coverLength=0;if(leftIdx+1==rightIdx){// 叶子结点return;}int mid=segTree[nodeIdx].mid();build(nodeIdx*2+1, leftIdx, mid);// 构造左子树build(nodeIdx*2+2,mid,rightIdx);// 构造右子树}/** * 更新线段树 * @param nodeIdx * @param a 扫描到的线段的左边界 * @param b 扫描到的线段的右边界 * @param cover */public void update(int nodeIdx,int a,int b,int cover){Node node=segTree[nodeIdx];if(node.left==a&&node.right==b){// 重合node.cover+=cover;getLen(nodeIdx);return;}int mid=node.mid();if (b <= mid) {// 更新左子树update(nodeIdx << 1 | 1, a, b, cover);} else if (a >= mid) {// 更新右子树update(nodeIdx << 1 | 2, a, b, cover);} else {// 左右子树都要更新update(nodeIdx << 1 | 1, a, mid, cover);update(nodeIdx << 1 | 2, mid, b, cover);}getLen(nodeIdx);}/** * 获取某个区间被覆盖的长度 * @param nodeIdx */public void getLen(int nodeIdx){Node node=segTree[nodeIdx];if(node.cover>0){// 被覆盖node.coverLength= X[node.right]-X[node.left];}else if(node.right==node.left+1){// 叶子结点,未被覆盖node.coverLength=0;}else{// 是线段,但没有完全覆盖,其覆盖长度需要根据孩子结点来计算node.coverLength=segTree[nodeIdx*2+1].coverLength+segTree[nodeIdx*2+2].coverLength;}}public static void main(String[] args) {Scanner sc=new Scanner(System.in);Main m=new Main();int mCase=1;float area=0;// 面积try{m.N=sc.nextInt();while(m.N!=0){if(m.N<0||m.N>100)throw new Exception("N不合法");m.input(sc);// 输入坐标m.transfer();// 对输入数据进行处理m.sort(m.lines,0,m.N*2);// 线段排序m.sort(m.X,0,m.N*2);// 横坐标排序int end=1;for(int i=1;i<2*m.N;i++){// 横坐标去重if(m.X[i]!=m.X[i-1]){m.X[end++]=m.X[i];}}end--;m.build(0, 0, end);// 构造线段树area=0;for(int i=0;i<2*m.N-1;i++){// 扫描,最后一条线段不用扫描了Line line=m.lines[i];int a=m.search(m.X, 0, end+1,line.x1);// 在坐标数组中找到线段起点和终点对应的数组下标int b=m.search(m.X, 0, end+1, line.x2);m.update(0, a, b, line.seq);// 更新线段树float dy=m.lines[i+1].y-line.y;// 当前线段和下一条线段y坐标的差值area+=m.segTree[0].coverLength*dy;// 计算面积}DecimalFormat format=new DecimalFormat("0.00");if(mCase==1)System.out.println();System.out.println("Build #"+mCase++);System.out.println("Total explored area: "+format.format(area));// 输出m.N=sc.nextInt();// 下一组输入}} catch (Exception e) {//e.printStackTrace();}finally{sc.close();}}/** * 保存线段 * @author fangxuan * */public class Line{public float x1,x2;public float y;public int seq;// 边序号,用来区别上下边public Line(float x1, float x2, float y) {this.x1 = x1;this.x2 = x2;this.y = y;}}/** * 线段树的结点 * @author fangxuan * */public class Node{public int left;// 保存左边界在横坐标数组中的下标public int right;// 保存右边界在横坐标数组中的下标public int cover;// 0 线段未被覆盖;1 被覆盖public float coverLength;// 该区间被覆盖的长度public int mid(){// 求中间值return (left+right)>>1;}}}

用List集合代替数组,会Memory Limit Exceed

import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;import java.util.Scanner;public class Main {public static class Line {public float x1, x2, y;public int seq;public Line(float x1, float x2, float y, int seq) {this.x1 = x1;this.x2 = x2;this.y = y;this.seq = seq;}}public static class Segment {public int left, right;public int cover;public float coverLength;public Segment lChild, rChild;public int mid() {return (left + right) >> 1;}}public static class SegTree {public Segment root;public List<Float> xList;public void build(List<Float> xList) {this.xList = xList;int size = xList.size();if (size == 0) {root = null;} elseroot = build(0, size - 1);}private Segment build(int left, int right) {Segment root = new Segment();root.cover = 0;root.coverLength = 0;root.left = left;root.right = right;if (left + 1 == right) {root.lChild = root.rChild = null;} else {int mid = root.mid();root.lChild = build(left, mid);root.rChild = build(mid, right);}return root;}public void update(Line line) {if (root == null)return;int a = search(xList, line.x1);int b = search(xList, line.x2);update(root, a, b, line.seq);}private void update(Segment root, int a, int b, int seq) {if (root.left == a && root.right == b) {root.cover += seq;getCoverLength(root);return;}int mid = root.mid();if (b <= mid) {update(root.lChild, a, b, seq);} else if (a >= mid) {update(root.rChild, a, b, seq);} else {update(root.lChild, a, mid, seq);update(root.rChild, mid, b, seq);}getCoverLength(root);}public void getCoverLength(Segment root) {if (root.cover > 0) {int r = root.right;int l = root.left;root.coverLength = xList.get(r) - xList.get(l);} else if (root.left + 1 == root.right) {root.coverLength = 0;} else {root.coverLength = root.lChild.coverLength+ root.rChild.coverLength;}}}public static int search(List<Float> xList, float x) {return Collections.binarySearch(xList, x);}public static void sortLine(List<Line> lines) {Collections.sort(lines, new Comparator<Line>() {@Overridepublic int compare(Line o1, Line o2) {return (int) (o1.y - o2.y);}});}public static void sortX(List<Float> xList) {Collections.sort(xList);int size = xList.size();for (int i = size - 1; i > 0; i--) {if (xList.get(i) == xList.get(i - 1)) {xList.remove(i);}}}public static void main(String[] args) {int n;int mCase = 0;float area = 0;int i = 0;List<Float> xList = new ArrayList<Float>();List<Line> lines = new ArrayList<Main.Line>();Scanner sc = new Scanner(System.in);n = sc.nextInt();while (n != 0) {xList.clear();lines.clear();float x1;float y1;float x2;float y2;for (i = 0; i < n; i++) {x1 = sc.nextFloat();y1 = sc.nextFloat();x2 = sc.nextFloat();y2 = sc.nextFloat();xList.add(x1);xList.add(x2);lines.add(new Line(x1, x2, y1, 1));lines.add(new Line(x1, x2, y2, -1));}sortX(xList);sortLine(lines);SegTree segTree = new SegTree();segTree.build(xList);if (segTree.root != null) {area = 0;for (i = 0; i < lines.size() - 1; i++) {segTree.update(lines.get(i));area += segTree.root.coverLength* (lines.get(i + 1).y - lines.get(i).y);}System.out.println("Build #" + (++mCase));System.out.printf("Total explored area: %.2f\n", area);}n = sc.nextInt();}sc.close();}}







0 0