塞奇威克的算法&韦恩,练习1.2.3:
编写一个带有命令行参数
N
的{{3}}客户端,min
和max
并生成N
随机2D区间,其宽度为 高度均匀分布在单位中的min
和max
之间 广场。在StdDraw
上绘制它们并打印成对的数量 相交的间隔和间隔的数量 彼此包含在内。
Interval2D公开以下API:
Interval2D(Interval1D x, Interval1D y)
boolean intersects(Interval2D)
boolean contains(Point2D)
double area()
void draw()
是否可以仅使用这些方法检查另一个Interval2D
是否包含在其中?
答案 0 :(得分:1)
A)了解情况:
以1D间隔定义2D间隔A和B:
A = Ixa x Iya = [x1a, x2a] x [y1a, y2a]
B = Ixb x Iyb = [x1b, x2b] x [y1b, y2b]
然后
A is contained in B, iff
Ixa = [x1a, x2a] is contained in Ixb [x1b, x2b] and
Iya = [y1a, y2a] is contained in Iyb = [y1b, y2b].
使用
I1 = [a, b] is contained in I2 = [c, d] iff c <= a and b <= d.
这类似于Interval2D(http://algs4.cs.princeton.edu/12oop/Interval2D.java.html)和Intervall1D(http://algs4.cs.princeton.edu/12oop/Interval1D.java.html)中交叉方法的实现,只是它们测试条件的逻辑逆。
B)现在你的方法:
如果检查左下角(x1a,y1a)和右上角(x2a,y2a)点,则包含(Point2D)应允许进行测试:
A is contained in B, iff B contains (x1a, y1a) and B contains (x2a, y2a).
丑陋的是,虽然Interval1D有getters访问私有左右坐标,但Interval2D没有访问它的私有x和y(一维)间隔。 你可以从它的toString()输出解析它们,但这是丑陋和太多的工作。 创建一些超类
public class Rect {
public Interval1D x;
public Interval1D y;
public Interval2D r;
Rect(Interval1D px, Interval1D py) {
x = px;
y = py;
r = new Interval2D(px, py);
}
public boolean contains(Rect that) {
if (!this.r.contains(new Point2D(that.x.left(), that.y.left()))) return false;
if (!this.r.contains(new Point2D(that.x.right(), that.y.right()))) return false;
return true;
}
}
使用它只是丑陋。
答案 1 :(得分:1)
您可以在Interval1D中使用left()和right()方法,在创建2D间隔期间预先保存它们。
我这样做了
int intersect = 0;
int contain = 0;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
if (arr2D[i].intersects(arr2D[j])){
intersect++;
}
if ( (arrX[i].left() <= arrX[j].left() && arrX[i].right() >= arrX[j].right())
&& (arrY[i].left() <= arrY[j].left() && arrY[i].right() >= arrY[j].right())) {
contain++;
}
}
}
答案 2 :(得分:0)
使用间隔的上限和下限检查交叉点更有意义。从理论上讲,应该可以只使用列出的方法,但这样做有效可能会很棘手。如果Interval A包含Interval b,那么B中的每个点也都在A中。因此我们可以迭代每个点(如果坐标系基于int而不是double)并检查这个条件。 如果我们面对双打,那么可以使用修改后的技术来生成一个包含方法,该方法将以高概率正确运行。
//Iterate over some subset of points.
if(b.contains(pointP) && !a.contains(pointP))
return false;
诀窍是找到合适的子集。但我认为保证总是正确的算法要困难得多。考虑一维情况。如果间隔A = (0.5,Math.PI/6)
和B = [0.4,Math.PI/6]
。显然B包含A,但这些方法都不能帮助我们看到它们都具有相同的正确终点,但B 包括那个点,而A则没有。
这些方法如何帮助我们区分这个例子:
A = (0.5,Math.PI/6]
和B = [0.4,Math.PI/6)
现在只需要选择一点来表明B不包含A:Math.PI/6
这让我觉得这样的算法几乎是不可能的。
答案 3 :(得分:0)
我的解决方案在这里:
package exercise.chapter2.section2;
import edu.princeton.cs.algs4.Interval1D;
import edu.princeton.cs.algs4.Interval2D;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
public class Ex1_2_03 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int N = Integer.parseInt(args[0]);
double min = Double.parseDouble(args[1]);
double max = Double.parseDouble(args[2]);
MyInterval2D[] boxes = new MyInterval2D[N];
for (int i = 0; i < N; i++) {
double width = StdRandom.uniform(min, max);
double height = StdRandom.uniform(min, max);
double xlo = StdRandom.uniform(width, 1.0 - width);
double xhi = xlo + width;
double ylo = StdRandom.uniform(height, 1.0 - height);
double yhi = ylo + height;
boxes[i] = new MyInterval2D(new Interval1D(xlo, xhi), new Interval1D(ylo, yhi));
boxes[i].draw();
}
int cintersects = 0;
int ccontained = 0;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
if (boxes[i].intersects(boxes[j])) {
cintersects++;
}
}
}
for (int i = 0; i < N; i++) {
boxes[i].draw();
for (int j = 0; j < N; j++) {
if (i != j && boxes[j].contains(boxes[i])) {
ccontained++;
break;
}
}
}
StdOut.println(cintersects);
StdOut.println(ccontained);
}
}
class MyInterval2D extends Interval2D {
private Interval1D xint;
private Interval1D yint;
public MyInterval2D(Interval1D xint, Interval1D yint) {
super(xint, yint);
this.xint = xint;
this.yint = yint;
}
public boolean contains(MyInterval2D box) {
if (xint.contains(box.xint.min()) && xint.contains(box.xint.max()) && yint.contains(box.yint.min()) && yint.contains(box.yint.max())) {
return true;
}
return false;
}
}