Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 求所有矩形面积的算法_Algorithm - Fatal编程技术网

Algorithm 求所有矩形面积的算法

Algorithm 求所有矩形面积的算法,algorithm,Algorithm,假设我们得到4个点的矩形:它们的(x1,y1),…,(x4,y4) 我们要计算它们覆盖的总面积。我们要计算总面积,如果更多的矩形重叠,我们只计算一次这个面积 我并不是真的在寻找完成的解决方案,伪代码或一些算法和数据结构的链接在这里有用将不胜感激 矩形的形式是:由三个整数给出:左位置、右位置和高度。例如: L:0R:2H:2 L:1 R:3 H:3 L:-1R:4H:1 总面积为:10 x轴的最大值从-1e9到1e9,从x=L开始,到x=R结束 y不能小于0,并且始终从y=0开始,到y=H结束。让

假设我们得到4个点的矩形:它们的(x1,y1),…,(x4,y4) 我们要计算它们覆盖的总面积。我们要计算总面积,如果更多的矩形重叠,我们只计算一次这个面积

我并不是真的在寻找完成的解决方案,伪代码或一些算法和数据结构的链接在这里有用将不胜感激

矩形的形式是:由三个整数给出:左位置、右位置和高度。例如:

L:0R:2H:2

L:1 R:3 H:3

L:-1R:4H:1

总面积为:10

x轴的最大值从-1e9到1e9,从x=L开始,到x=R结束
y不能小于0,并且始终从y=0开始,到y=H结束。让我们假设矩形的整数坐标范围非常小,比如说0到10。然后,一种简单的方法是创建网格并在其上绘制矩形:

占用的“像素”可以存储在一个集合中,也可以是位图中的设置位。当矩形重叠时,交叉点仅被标记为再次被占用,因此仅对区域贡献一次。面积是被占用单元的数量

对于大维度,数据结构将变得太大。此外,绘制几百万像素宽的矩形也会很慢

但当我们使用压缩坐标时,这种技术仍然可以应用。然后,网格只有矩形的实际坐标。单元格的宽度和高度可变。单元格的数量取决于矩形的数量,但与最小和最大坐标无关:

算法如下所示:

  • 找到所有唯一的x坐标。按升序对它们进行排序,并将(坐标、索引)对存储在字典中以便于查找
  • 对y坐标执行相同的操作
  • 绘制矩形:找到x和y范围的索引并占据它们之间的单元格
  • 通过将所有占用单元的面积相加来计算面积

这些矩形的底面为y=0?我想那是真的。因此,从远处看,它们就像城市中的建筑物。你在试图追踪天际线

将矩形存储在一个数组中,以便可以将数组索引用作唯一ID。将每个左右矩形边表示为一个“事件”,该事件包括其所属矩形的ID和相应边的x坐标。将所有事件放在列表EL中,并按x坐标排序。最后,您将需要一个动态排序的矩形ID集(例如Java树集),它按相应的矩形高度降序排序。它被称为SL,即“扫描线”。由于其排序方式,SL.first始终是SL当前引用的最高矩形的ID

现在,您可以按如下方式绘制矩形集合的轮廓:

SL = <empty>  // sweep line
x0 = EL.first.left // leftmost x among all rectangle edges
lastX = x0
for each event E in EL // process events left-to-right
  Let y0 = if SL.isEmpty then 0 else SL.first.height // current y
  if E.ID in SL // event in SL means sweep line is at rectangle's right edge
    remove E.ID from SL
  else // event means sweep line is a new rectangle's left edge
    add E.ID to SL
  Let y1 = if SL.isEmpty then 0 else SL.first.height // new y
  if y1 != y0
    output line seg (lastX, y0) -> (E.x, y0)
    output line seg (E.x, y0) -> (E.x, y1)
    lastX = E.x
output final line seg (lastX, 0) -> (x0, 0)
SL=//扫描线
x0=EL.first.left//所有矩形边中最左边的x
lastX=x0
对于EL/中的每个事件E,从左到右处理事件
设y0=如果SL.isEmpty,则0 else SL.first.height//当前y
若SL中的E.ID//则SL中的事件表示扫描线位于矩形的右边缘
从SL中删除E.ID
else//event表示扫描线是新矩形的左边缘
将E.ID添加到SL
设y1=如果SL.isEmpty,则0 else SL.first.height//new y
如果y1!=y0
输出线分段(lastX,y0)->(E.x,y0)
输出线seg(E.x,y0)->(E.x,y1)
lastX=E.x
输出最终行seg(lastX,0)->(x0,0)
因为这听起来像是家庭作业或是面试问题,所以我将让您修改此算法,以提供扫掠形状的区域,而不是绘制其边缘

添加

只是为了好玩:

import java.util.ArrayList;
import static java.lang.Integer.compare;
import static java.util.Arrays.stream;
import static java.util.Collections.sort;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

class SkyLine {
  static class Rectangle {
    final int left;
    final int right;
    final int height;
    Rectangle(int left, int right, int height) {
      this.left = left;
      this.right = right;
      this.height = height;
    }
  }
  static class Event implements Comparable<Event> {
    final int x;
    final int id;
    public Event(int x, int id) {
      this.x = x;
      this.id = id;
    }
    @Override
    public int compareTo(Event e) { return compare(x, e.x); }
  }

  final List<Rectangle> rectangles = new ArrayList<>();  
  final Comparator byHeightDescending = 
      (Comparator<Integer>) (Integer a, Integer b) -> 
          compare(rectangles.get(b).height, rectangles.get(a).height);
  final SortedSet<Integer> scanLine = new TreeSet<>(byHeightDescending);
  final List<Event> events = new ArrayList<>();

  SkyLine(Rectangle [] data) {
    stream(data).forEach(rectangles::add);
    int id = 0;
    for (Rectangle r : rectangles) {
      events.add(new Event(r.left, id));
      events.add(new Event(r.right, id));
      ++id;
    }
    sort(events);
  }

  int area() {
    int area = 0;
    Event ePrev = null;
    for (Event e : events) {
      if (ePrev != null) area += (e.x - ePrev.x) * rectangles.get(scanLine.first()).height;
      if (!scanLine.remove(e.id)) scanLine.add(e.id);
      ePrev = e;
    }
    return area;
  }

  public static void main(String [] args) {
    Rectangle [] data = {
      new Rectangle(0, 2, 2),
      new Rectangle(1, 3, 3),
      new Rectangle(-1, 4, 1),
    };
    int area = new SkyLine(data).area();
    System.out.println(area);
  }
}
import java.util.ArrayList;
导入静态java.lang.Integer.compare;
导入静态java.util.Arrays.stream;
导入静态java.util.Collections.sort;
导入java.util.Comparator;
导入java.util.List;
导入java.util.SortedSet;
导入java.util.TreeSet;
类天际线{
静态类矩形{
最后的整数左;
最终权利;
最终整数高度;
矩形(整数左、整数右、整数高){
this.left=左;
这个。右=右;
高度=高度;
}
}
静态类事件实现了可比较的{
最终整数x;
最终int id;
公共事件(整数x,整数id){
这个.x=x;
this.id=id;
}
@凌驾
公共int比较(事件e){返回比较(x,e.x);}
}
最终列表矩形=新的ArrayList();
最终比较器按高度递减=
(比较器)(整数a、整数b)->
比较(矩形.获取(b).高度,矩形.获取(a).高度);
最终分拣集扫描线=新树集(通过高度下降);
最终列表事件=新的ArrayList();
天际线(矩形[]数据){
流(数据).forEach(矩形::add);
int id=0;
用于(矩形r:矩形){
添加(新事件(右左,id));
添加(新事件(右,id));
++身份证;
}
排序(事件);
}
内部区域(){
int面积=0;
事件ePrev=null;
对于(事件e:事件){
如果(ePrev!=null)区域+=(e.x-ePrev.x)*矩形.get(scanLine.first()).height;
如果(!scanLine.remove(e.id))scanLine.add(e.id);
ePrev=e;
}
返回区;
}
公共静态void main(字符串[]args){
矩形[]数据={
新矩形(0,2,2),
新矩形(1,3,3),
新矩形(-1,4,1),
};
int area=新的天际线(数据).area();
系统输出打印LN(面积);
}
}

这个问题可能更适合于。您的问题不清楚,您是在谈论矩形的离散化还是什么?通常情况下,如果矩形R1已排序(从左下到右上)坐标x11、y11、x12、y12和R2 x21、y21、x22、y22,则如果它们重叠(x21所有矩形轴是否对齐(y1=y2;y3=y4;x2=x3和x1=x4)?是否