Princeton Algotithms Collinear Points

2023-10-16 07:30

本文主要是介绍Princeton Algotithms Collinear Points,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Princeton Algotithms Collinear Points

普林斯顿大学算法课第 3 次作业“共线点”。

虽然本次作业给出了暴力方法和快速方法,但是不要以为就能拿到很高的分数。

同样地,想要通过,非常简单,只要答案正确就行了,很容易通过。

但是想要拿到高分,还是不容易的。

以下代码获得 100 分,其中需要注意的点我罗列一下,具体可以看代码理解。

注意与 x 轴平行的点,斜率必须返回正 0。

注意这里必须返回正 0,否则 0 带有正负号,会使得平行于 x 轴的排序出错。例如 (0, 5), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5) 以 (1, 5) 为排序时结果是 (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (0, 5),(0, 5) 到最后了。因此不能直接一减、一除,那样的 0 是有正负号的。

事实上这一点,在 API 文档中已经提示地很清楚了。

Returns the slope between this point and the specified point.
Formally, if the two points are (x0, y0) and (x1, y1), then the slope is (y1 - y0) / (x1 - x0). For completeness, the slope is defined to be +0.0 if the line segment connecting the two points is horizontal; Double.POSITIVE_INFINITY if the line segment is vertical; and Double.NEGATIVE_INFINITY if (x0, y0) and (x1, y1) are equal.
Points array passsed to the constructor can be changed by some other parts of the code while construction is still in progress.

所以进入构造函数以后,先无脑做 copy。

由于是不可变类型,所以构造的时候就可以直接把结果计算好,然后缓存起来,不需要每次调用的时候去算,调用就直接返回缓存的数据就好了。但是注意,必须返回一份拷贝,以保证不可变。

Stores a reference to an externally mutable object in the instance variable ‘points’, exposing the internal representation of the class.

Instead, create a defensive copy of the object referenced by the parameter variable ‘points’ and store that copy in the instance variable ‘points’.

check that data type is immutable by testing whether each method returns the same value, regardless of any intervening operations

如何去重

Let’s say you have 5 points in their natural order a, b, c, d, e. When you have b as the anchor and sort the remaining points by slopeOrder, you want points with the same slope to appear in their natural order (i.e. … a, c, d, e, …).

To avoid adding the subsegment (b, c, d, e), whenever you start seeing a new slope (i.e. at a), you just need to check if b is less than a in terms of natural order – if it is not, it means b is not the first point in that segment, then you know you don’t need to add it.

import java.util.ArrayList;
import java.util.Arrays;public class BruteCollinearPoints {private final Point[] points;private final LineSegment[] cached;public BruteCollinearPoints(Point[] points) {if (points == null) {throw new IllegalArgumentException();}// Points array passsed to the constructor can be changed by some other parts of the code while construction is still in progress.this.points = Arrays.copyOf(points, points.length);for (Point point : this.points) {if (point == null) {throw new IllegalArgumentException();}}Arrays.sort(this.points);for (int i = 0; i < this.points.length; i++) {if (i > 0 && Double.compare(this.points[i].slopeTo(this.points[i - 1]), Double.NEGATIVE_INFINITY) == 0) {throw new IllegalArgumentException();}}// Stores a reference to an externally mutable object in the instance variable 'points', exposing the internal representation of the class.// Instead, create a defensive copy of the object referenced by the parameter variable 'points' and store that copy in the instance variable 'points'.cached = cache();}private LineSegment[] cache() {ArrayList<LineSegment> list = new ArrayList<>();int n = points.length;for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {for (int k = j + 1; k < n; k++) {for (int m = k + 1; m < n; m++) {Point p = points[i];Point q = points[j];Point r = points[k];Point s = points[m];double slope1 = p.slopeTo(q);double slope2 = p.slopeTo(r);double slope3 = p.slopeTo(s);if (Double.compare(slope1, slope2) == 0 && Double.compare(slope2, slope3) == 0) {list.add(new LineSegment(p, s));}}}}}LineSegment[] segments = new LineSegment[list.size()];return list.toArray(segments);}public int numberOfSegments() {return cached.length;}public LineSegment[] segments() {// check that data type is immutable by testing whether each method// returns the same value, regardless of any intervening operationsreturn Arrays.copyOf(cached, cached.length);}
}
/**************************************************************************  Compilation:  javac LineSegment.java*  Execution:    none*  Dependencies: Point.java**  An immutable data type for Line segments in the plane.*  For use on Coursera, Algorithms Part I programming assignment.**  DO NOT MODIFY THIS CODE.**************************************************************************/public class LineSegment {private final Point p;   // one endpoint of this line segmentprivate final Point q;   // the other endpoint of this line segment/*** Initializes a new line segment.** @param  p one endpoint* @param  q the other endpoint* @throws NullPointerException if either <tt>p</tt> or <tt>q</tt>*         is <tt>null</tt>*/public LineSegment(Point p, Point q) {if (p == null || q == null) {throw new NullPointerException("argument is null");}this.p = p;this.q = q;}/*** Draws this line segment to standard draw.*/public void draw() {p.drawTo(q);}/*** Returns a string representation of this line segment* This method is provide for debugging;* your program should not rely on the format of the string representation.** @return a string representation of this line segment*/public String toString() {return p + " -> " + q;}/*** Throws an exception if called. The hashCode() method is not supported because* hashing has not yet been introduced in this course. Moreover, hashing does not* typically lead to good *worst-case* performance guarantees, as required on this* assignment.** @throws UnsupportedOperationException if called*/public int hashCode() {throw new UnsupportedOperationException();}}
import java.util.ArrayList;
import java.util.Arrays;public class FastCollinearPoints {private final Point[] points;private final LineSegment[] cached;public FastCollinearPoints(Point[] points) {if (points == null) {throw new IllegalArgumentException();}// Points array passsed to the constructor can be changed by some other parts of the code while construction is still in progress.this.points = Arrays.copyOf(points, points.length);for (Point point : this.points) {if (point == null) {throw new IllegalArgumentException();}}Arrays.sort(this.points);for (int i = 0; i < this.points.length; i++) {if (i > 0 && Double.compare(this.points[i].slopeTo(this.points[i - 1]), Double.NEGATIVE_INFINITY) == 0) {throw new IllegalArgumentException();}}// Stores a reference to an externally mutable object in the instance variable 'points', exposing the internal representation of the class.// Instead, create a defensive copy of the object referenced by the parameter variable 'points' and store that copy in the instance variable 'points'.cached = cache();}public int numberOfSegments() {return cached.length;}public LineSegment[] segments() {// check that data type is immutable by testing whether each method// returns the same value, regardless of any intervening operationsreturn Arrays.copyOf(cached, cached.length);}private LineSegment[] cache() {ArrayList<LineSegment> list = new ArrayList<>();Arrays.sort(points);for (Point p: points) {Point[] pp = Arrays.copyOf(points, points.length);if (pp.length < 4) {continue;}Arrays.sort(pp, p.slopeOrder());int begin = 1;int end = 1;double last = p.slopeTo(pp[end]);for (int j = 2; j < pp.length; j++) {double slope = p.slopeTo(pp[j]);if (Double.compare(last, slope) != 0) {if (end - begin >= 2) {// end - begin + 1 有 3 个以上了,加上 p(即pp[0]) 就至少有 4 个了if (p.compareTo(pp[begin]) < 0) {// 去掉子线段/*Let's say you have 5 points in their natural order a, b, c, d, e.When you have b as the anchor and sort the remaining points by slopeOrder, you want points with the same slope to appear in their natural order (i.e. ... a, c, d, e, ...).To avoid adding the subsegment (b, c, d, e), whenever you start seeing a new slope (i.e. at a), you just need to check if b is less than a in terms of natural order- if it is not, it means b is not the first point in that segment, then you know you don't need to add it.*/list.add(new LineSegment(p, pp[end]));}}last = slope;begin = j;}end = j;}if (end - begin >= 2) {if (p.compareTo(pp[begin]) < 0) {list.add(new LineSegment(p, pp[end]));}}}LineSegment[] segments = new LineSegment[list.size()];return list.toArray(segments);}
}
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;public class Client {public static void main(String[] args) {// read the n points from a fileIn in = new In(args[0]);int n = in.readInt();Point[] points = new Point[n];for (int i = 0; i < n; i++) {int x = in.readInt();int y = in.readInt();points[i] = new Point(x, y);}// draw the pointsStdDraw.enableDoubleBuffering();StdDraw.setXscale(0, 32768);StdDraw.setYscale(0, 32768);for (Point p : points) {p.draw();}StdDraw.show();// print and draw the line segmentsFastCollinearPoints collinear = new FastCollinearPoints(points);for (LineSegment segment : collinear.segments()) {StdOut.println(segment);segment.draw();}points[0] = new Point(0, 0);for (LineSegment segment : collinear.segments()) {StdOut.println(segment);segment.draw();}StdDraw.show();}
}
/*******************************************************************************  Compilation:  javac Point.java*  Execution:    java Point*  Dependencies: none**  An immutable data type for points in the plane.*  For use on Coursera, Algorithms Part I programming assignment.*******************************************************************************/import java.util.Arrays;
import java.util.Comparator;import edu.princeton.cs.algs4.StdDraw;public class Point implements Comparable<Point> {private final int x;     // x-coordinate of this pointprivate final int y;     // y-coordinate of this point/*** Initializes a new point.** @param x the <em>x</em>-coordinate of the point* @param y the <em>y</em>-coordinate of the point*/public Point(int x, int y) {/* DO NOT MODIFY */this.x = x;this.y = y;}/*** Draws this point to standard draw.*/public void draw() {/* DO NOT MODIFY */StdDraw.point(x, y);}/*** Draws the line segment between this point and the specified point* to standard draw.** @param that the other point*/public void drawTo(Point that) {/* DO NOT MODIFY */StdDraw.line(this.x, this.y, that.x, that.y);}/*** Returns the slope between this point and the specified point.* Formally, if the two points are (x0, y0) and (x1, y1), then the slope* is (y1 - y0) / (x1 - x0). For completeness, the slope is defined to be* +0.0 if the line segment connecting the two points is horizontal;* Double.POSITIVE_INFINITY if the line segment is vertical;* and Double.NEGATIVE_INFINITY if (x0, y0) and (x1, y1) are equal.** @param that the other point* @return the slope between this point and the specified point*/public double slopeTo(Point that) {/* YOUR CODE HERE */if (x == that.x && y == that.y) {return Double.NEGATIVE_INFINITY;} else if (x == that.x) {return Double.POSITIVE_INFINITY;} else if (y == that.y) {return 0;// 注意这里必须返回正 0,否则 0 带有正负号,会使得平行于 x 轴的排序出错// 例如 (0, 5), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5) 以 (1, 5) 为排序时结果是// (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (0, 5)// (0, 5) 到最后了} else {return (double) (y - that.y) / (x - that.x);}}/*** Compares two points by y-coordinate, breaking ties by x-coordinate.* Formally, the invoking point (x0, y0) is less than the argument point* (x1, y1) if and only if either y0 < y1 or if y0 = y1 and x0 < x1.** @param that the other point* @return the value <tt>0</tt> if this point is equal to the argument* point (x0 = x1 and y0 = y1);* a negative integer if this point is less than the argument* point; and a positive integer if this point is greater than the* argument point*/@Overridepublic int compareTo(Point that) {/* YOUR CODE HERE */if (y != that.y) {return Integer.compare(y, that.y);} else {return Integer.compare(x, that.x);}}/*** Compares two points by the slope they make with this point.* The slope is defined as in the slopeTo() method.** @return the Comparator that defines this ordering on points*/public Comparator<Point> slopeOrder() {/* YOUR CODE HERE */return new Comparator<Point>() {@Overridepublic int compare(Point o1, Point o2) {return Double.compare(slopeTo(o1), slopeTo(o2));}};}/*** Returns a string representation of this point.* This method is provide for debugging;* your program should not rely on the format of the string representation.** @return a string representation of this point*/@Overridepublic String toString() {/* DO NOT MODIFY */return "(" + x + ", " + y + ")";}/*** Unit tests the Point data type.*/public static void main(String[] args) {/* YOUR CODE HERE */Point p1 = new Point(0, 0);Point p2 = new Point(1, 1);System.out.println(p1.compareTo(p2));System.out.println(p1.slopeTo(p2));Point[] pp = new Point[3];pp[0] = new Point(2, 1);pp[1] = new Point(0, 0);pp[2] = new Point(1, 1);Arrays.sort(pp, pp[1].slopeOrder());System.out.println(Arrays.toString(pp));}
}

欢迎关注我的个人博客以优秀文章:凝神长老和他的朋友们(https://www.jxtxzzw.com)

也欢迎关注我的其他平台:知乎( https://s.zzw.ink/zhihu )、知乎专栏( https://s.zzw.ink/zhuanlan )、哔哩哔哩( https://s.zzw.ink/blbl )、微信公众号( 凝神长老和他的朋友们 )
凝神长老的二维码们

这篇关于Princeton Algotithms Collinear Points的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/219996

相关文章

纪念一下自己的Coursera Princeton Algorithm的课程第一个assignment

今天终于完成了第一个Union-Find的assignment,之前觉得特别的难,可是最后自己也搞定了。而且是100%满分。 自己后来plot了一下自己的分数,也许这就是学习曲线吧。刚开始不会,到后来中期显著提高,但是要到100%,那就要经历更多的波折,甚至是下降都有可能。最后才能达到100%满分。 我觉得最有用的还是下面这段源代码: /*************************

C# 使用中点查找矩形的角(Find Corners of Rectangle using mid points)

考虑一个矩形 ABCD,我们给出了边 AD 和 BC 中点(分别为 p 和 q)的坐标以及它们的长度 L(AD = BC = L)。现在给定参数,我们需要打印 4 个点 A、B、C 和 D 的坐标。 例子:  输入:p = (1, 0)         q = (1, 2)         L = 2 输出:(0,0),(0,2),(2,2),(2,0) 解释: 打

【译】PCL官网教程翻译(18):估计一组点的视点特征直方图(VFH)签名 - Estimating VFH signatures for a set of points

英文原文查看 估计一组点的视点特征直方图(VFH)签名 本文描述了视点特征直方图([VFH])描述符,这是一种针对聚类(如对象)识别和6DOF姿态估计问题的点簇表示方法。 下图展示了一个VFH识别和姿态估计的例子。给定一组火车数据(除最左边的点云外,最上面一行、最下面一行),学习一个模型,然后使用一个云(最左边的部分)查询/测试模型。匹配的结果按从最好到最差的顺序从左到右从左下角开始。有关更多

On Segment's Own Points(可用区间长度)

题目连接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=42180#problem/A 思路一: 排序合并,但是比较繁琐 代码: #include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,l,r; struct node

Codeforces Round #331 (Div. 2)C. Wilbur and Points(模拟+STL)

题目链接 题意:就是给出一组点,然后问如果Xa>=Xb&&Ya>=Yb的话,那么a点的编号必须必b点大,同时,点的权值要满足给出的w序列。 解法:先判断给出的w,与点的w的是不是能完全重合,不能的话就是no 然后,我们就按照给出的w顺序找出点的顺序,然后判断一下即可 AAA:比赛时候貌似又读错了题意,,昨天状态太差。。。 #include<bits/stdc++.h>using na

【数学 象限】HDU 1152 Brownie Points I

链接:井枯旋 题意很简单,给你奇数个点,中间一个点为中心点,也可以说是原点,这样,就有了四个象限,左上,右下象限的点的个数为O的得分,右上,左下象限的点的个数为S的得分,最后输出得分就可以了。连排序都不需要。。。 #include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <c

How Many Points of Intersection?

找规律题,最终可以简化为一个式子   How Many Points of Intersection?  We have two rows. There are a dots on the top row and b dots on the bottom row. We draw line segments connecting every dot on the top ro

poj 3090 Visible Lattice Points(数论:筛法打表欧拉函数)

和之前做过的一个题很像 对于size==4 从1到4考虑y坐标 不妨设x>=y y==1: (1,1) y==2: (1,2) y==3: (1, 3) (2, 3) y==4: (1, 4) (3, 4) 共6个满足条件,把x y交换下且去除(1, 1)的重复情况得到2×6-1=11 再加上(0,1) (1,0)两种情况得到13 所以结果应该为: 代码如下: #

lighoj 1088 Points in Segments | 二分

题意: 给你n个数,q个区间。让你求出每个区间所包含的数的个数。 思路: 一开始以为是线段树,不过看看数据范围,算了。。。 把n个数sort一遍,然后根据每个区间的两个边值进行二分,得出的结果相减即可。注意细节。 AC代码: #include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#in

python 自定义命令(entry_points)以及开发第三方库setuptools打包

突然想知道类似django-admin、you-get这种不用Python执行的自定义命令怎么实现的的,查了一下setuptools打包时配置一下entry_points可以实现。 工程结构 setup.py代码: #setup.pyfrom setuptools import setupsetup(name = "setuptoolsdemo",version = "1.0.0",au