Download Document

Document related concepts
no text concepts found
Transcript
Contest Algorithms
January 2016
15. Computational
Geometry Topics
An examination of some important CG topics;
A taster of a very large research area.
Contest Algorithms: 15. CG Topics
1
Overview
1. Intersection of Multiple Line Segments

the sweeping algorithm
2. Finding the Convex Hull

Graham Scan, Jarvis' March (Gift Wrapping)
3. Finding the Closest Pair of Points

divide-and-conquer (O(n· log n)
1. Intersection of Multiple Line Segments
1.1. Multiple Line Segments
1.2. A Brute-Force Algorithm
1.3. The Sweeping Algorithm
1.4. Implementing Sweeping
1.1. Multiple Line Segments
Input: a set of n line segments in the plane.
Output: all intersections, and for each intersection the
involved segments.
.
1.2. A Brute-Force Algorithm
Look at each pair of segments, and check if they intersect.
If so, output the intersection.
n(n-1)/2 comparison are needed in the worst case,
so the running time is O(n2)
But the lines are sparsly distributed in practice:
• Most segments do not intersect, or if they do,
only with a few other segments
Need a faster algorithm that deals with such situations!
Code
see SegmentsIntersect.java
public static ArrayList<Pair<Segment,Segment>>
findIntersectsNaive(ArrayList<Segment> segs)
/* Determines whether any two segs in the given set intersect
using the brute force approach in O(n^2).
*/
{ ArrayList<Pair<Segment,Segment>> segPairs = new ArrayList<>();
for (int i = 0; i < segs.size()-1; i++) {
for (int j = i + 1; j < segs.size(); j++) {
if (segs.get(i).intersects(segs.get(j)))
segPairs.add( new Pair<Segment,Segment>(segs.get(i), segs.get(j)) );
}
}
return segPairs;
} // end of findIntersectsNaive()
Contest Algorithms
6
Usage
ArrayList<Segment> segs = new ArrayList<>();
segs.add( new Segment( new Pt(1,1), new Pt(4,3)));
segs.add( new Segment( new Pt(2,4), new Pt(6,1)));
segs.add( new Segment( new Pt(3,5), new Pt(6,3)));
segs.add( new Segment( new Pt(5,1), new Pt(7,5)));
ArrayList<Pair<Segment,Segment>> segPairs =
SegmentsIntersect.findIntersectsNaive(segs);
System.out.println("Intersecting segments:");
for(Pair<Segment,Segment> pair : segPairs)
System.out.println(" " + pair.getX() + " with " + pair.getY());
Contest Algorithms:15. CG Topics
7
Results
Contest Algorithms:15. CG Topics
8
1.3. The Sweeping Algorithm
Avoid testing pairs of segments that are far apart.
Idea: imagine a vertical sweep line passes through the given
set of line segments, from left to right.
Sweep
line
also known as the "Bentley-Ottmann" Algorithm
and the Sweep Line Algorithm
O(n log n)
Non-Degeneracy Assumptions
No segment is vertical.
// this means that the sweep line will always hit a
segment at a point.
If an input segment is vertical, then it is
rotated clockwise by a tiny angle.
Sweep Line Status
The set of segments intersecting the sweep line.
It changes as the sweep line moves, but not continuously.
Updates of status happen only at event points.
A
G
C
T
event points
endpoints
intersections
Ordering Segments
A total order over the segments that intersect the current
position of the sweep line:
later
B>C>D
(A and E not in
the ordering)
B
A
C
E
C>D
(B drops out of
the ordering)
D
At an event point, the sequence of segments changes:
 Update the status.
 Detect the intersections.
Status Update (1)
Event point is the left endpoint of a segment.
K
L
O
 Check if L intersects with the
segment above (K) and the
segment below (M).
M
N
K, M, N
A new segment L intersecting
the sweep line
new event
point
K, L, M, N
 Intersection(s) are new
event points.
Status Update (2)
Event point is an intersection.
K
O
L
 Check intersection with new
neighbors (M with O and
L with N).
M
 Intersection(s) are new
event points.
N
O, L, M, N
 The two intersecting segments
(L and M) change order.
O, M, L, N
Status Update (3)
Event point is a lower endpoint of a segment.
K
O
 Check if they (O and L)
intersect.
L
M
 Intersection is new event
point.
N
O, M, L, N
 The two neighbors (O and L)
become adjacent.
O, L, N
1.4. Implementing Sweeping
The algorithm manages two kinds of data:
 1. The sweep line status gives the relationships among the
objects intersected by the sweep line.
 2. The event point queue is a sequence of event points
that defines the halting positions of the sweep line.
Event Point Queue Operations
Manages the ordering of event points:
• by x-coordinates
• by y-coordinates in case of a tie in x-coordinates
Supports the following operations on a segment s.
 fetching the next event
 inserting an event
// O(log m)
// O(log m)
m = no. of event
points currently
being managed
Every event point p is stored with all segments starting at p.
Data structure: a balanced binary search tree
(e.g., red-black tree).
Sweep Line Operations
 The sweep line status (T) requires the following operations:
 INSERT(T, s): insert segment s into T.
 DELETE(T, s): delete segment s from T.
 ABOVE(T, s): return the segment immediately above segment s in T.
 BELOW(T, s): return the segment immediately below segment s in T.
 Use a balanced binary search tree for T (e.g. Red-black trees): O(log
n) for each operation
Segments intersect Pseudocode
ANY-SEGMENTS-INTERSECT(S)
1 T = Ø
2 sort the endpoints of the segments in S from left to right,
breaking ties by putting left endpoints before right endpoints
and breaking further ties by putting points with lower
y-coordinates first
3 for (each point p in the sorted list of endpoints) {
4
if (p is the left endpoint of a segment s) {
5
INSERT(T, s)
6
if (ABOVE(T, s) exists and intersects s) or
(BELOW(T, s) exists and intersects s)
7
return TRUE
}
8
if (p is the right endpoint of a segment s) {
9
if (both ABOVE(T, s) and BELOW(T, s) exist) and
(ABOVE(T, s) intersects BELOW(T, s))
10
return TRUE
11
DELETE(T, s)
}
}
12 return FALSE
Execution Example
e
d
b
the intersection of segments d
and b is detected when
segment c is deleted
Java Code
 https://github.com/bkiers/CompGeom/blob/master/src/
main/compgeom/util/SweepLine.java
 and EventQueue.java, Event.java
 (This code does not give correct answers in every case,
but perhaps this is due to the many changes I made to
get the code to work with my CG classes.)
Contest Algorithms:15. CG Topics
21
1.5. An Alternative to Sweeping
 My SegmentsIntersect.findIntersects() orders the segments'
start and end points in left-to-right order.
 It adds and removes segments to a list based on their start
and end points, and the current point being considered.
 The running time in the worst case is O(n2), but is much faster on
average.
 The coding is much shorter than using SweepLine
 It relies on a Pt object linking to its parent Segment object
Contest Algorithms:15. CG Topics
22
Code
public static ArrayList<Pair<Segment,Segment>>
findIntersects(ArrayList<Segment> segs)
{
ArrayList<Pair<Segment,Segment>> segPairs = new ArrayList<>();
// to hold the pairs of lines that interect
ArrayList<Segment> segsList = new ArrayList<Segment>();
ArrayList<Pt> points = new ArrayList<Pt>();
for (Segment s : segs) {
s.p1.setSegment(s); // link start-point p1 to its segment s
points.add(s.p1);
s.p2.setSegment(s); // link end-point p2 to its segment s
points.add(s.p2);
}
Collections.sort(points);
System.out.println("Sorted points: " +
Arrays.toString(points.toArray()));
:
Contest Algorithms:15. CG Topics
23
// look at segments based on their left-to right point order
for (Pt pt : points) {
Segment pSeg = pt.getSegment();
if (pt.isStartPoint()) { // check seg against every seg in list
for(Segment s : segsList) {
if (pSeg.intersects(s))
segPairs.add( new Pair<Segment,Segment>(pSeg,s) );
// store intersection pair of segment
}
segsList.add(pSeg);
// add seg to list since reached its start-point
}
else
// is end-point, so remove the segment from the list
segsList.remove(pSeg);
}
return segPairs;
} // end of findIntersects()
Contest Algorithms:15. CG Topics
24
Results
Contest Algorithms:15. CG Topics
25
2. Finding the Convex Hull
2.1. Convex & Concave Sets
2.2. The Convex Hull
2.3. The Graham Scan
2.4. Jarvis’ March
2.1. Convex and Concave Sets
A planar region R is called convex if and only if for any pair
of points p, q in R, the line segment pq lies completely in R.
Otherwise, it is called concave.
p
p
R2
R1
q
q
Convex
Concave
2.2. The Convex Hull
The convex hull of a set of points P is the smallest
convex region that contains all of P.
Rubber band
When P is finite, its convex hull is the unique convex polygon
whose vertices are from P and that contains all points of P.
The Convex Hull Problem
Input: a set P = { p1 , p2 , …, pn } of points
Output: a list of vertices in the convex hull in counterclockwise order.
p5
Example
p9
p6
p2
p3
p8
hull = [ p5, p9, p2, p8, p10, p7 ]
p7
p1
p4
p10
Not all the points
in P are in the hull
2.3. The Graham Scan
p9
p11
p10
p6
p7
p8
p5
p3
p2
sort by polar angle
p0
O(n· log n)
p4
p1
The center point has the
minimum y-coordinate
Labels are in the polar angle order.
(What if two points have the same polar angle?)
How to break a tie?
A Turning Algorithm
 Consider each of the points in the sorted sequence.
 For each point, is moving from the two previously considered
points to this point a "left turn" or "right turn"?
 "Right turn": this means that the second-to-last point is not part
of the convex hull and should be removed.
 this process is continued for as long as the set of the last three points is a
"right turn"
 "Left turn": the algorithm moves to the next point in the
sequence.
Turning in Action
C is a left turn compared to A – B;
add C
X
D is a right turn compared to B - C;
remove C
D is a left turn compared to A - B;
add D
Code
public static ArrayList<Pt> grahamScan(Pt[] points)
{ // points[numPts-1] is different from points[0]
// defensive copy
see ConvexHullTests.java
int numPts = points.length;
Pt[] pts = new Pt[numPts];
for (int i = 0; i < numPts; i++)
pts[i] = points[i];
Pt lowPt = getLowestPoint(pts);
// sort by polar angle with respect to lowPt,
// breaking ties by distance to lowPt
Arrays.sort(pts, new PolarOrder(lowPt));
System.out.println("sorted pts: " + Arrays.toString(pts));
Stack<Pt> stk = new Stack<Pt>();
stk.push(pts[0]);
// lowest point
:
Contest Algorithms
33
// find index k1 of first point not equal to pts[0]
int k1;
for (k1 = 1; k1 < numPts; k1++)
if (!pts[0].equals(pts[k1]))
break;
if (k1 == numPts) {
System.out.println("All points are the same");
return null; // all pts equal
}
// find index k2 of first point not collinear with pts[0] and pts[k1]
int k2;
for (k2 = k1 + 1; k2 < numPts; k2++)
if (Pt.ccw(pts[0], pts[k1], pts[k2]) != 0)
break;
stk.push(pts[k2 - 1]); // pts[k2-1] is second extreme point
:
Contest Algorithms:15. CG Topics
34
// Graham scan;
for (int i = k2; i < numPts; i++) {
Pt top = stk.pop();
while (Pt.ccw(stk.peek(),top, pts[i]) <= 0)
top = stk.pop();
stk.push(top);
stk.push(pts[i]);
}
ArrayList<Pt> hull = new ArrayList<Pt>();
while(!stk.empty())
hull.add(0, stk.pop()); // reverse order
return hull;
} // end of grahamScan()
Contest Algorithms:15. CG Topics
35
public class PolarOrder implements Comparator<Pt>
{
private Pt lowPt;
see PolarOrder.java
public PolarOrder(Pt lowPt)
{ this.lowPt = lowPt; }
public int compare(Pt p1, Pt p2)
{
double cp = Pt.ccw(lowPt, p1, p2);
if (cp > 0)
return -1;
if (cp < 0)
return 1;
// collinear; order by distance from lowPt
double d1 = lowPt.dist(p1);
double d2 = lowPt.dist(p2);
if (d1 < d2)
return -1;
if (d1 > d2)
return 1;
return 0;
} // end of compare()
} // end of PolarOrder class
Contest Algorithms:15. CG Topics
36
Usage
see ConvexHullTexts.java
public static void main(String[] args) throws Exception
{ if (args.length != 1) {
System.out.println("Usage: java ConvexHullTests <data-file>");
return;
}
Scanner sc = new Scanner(new File(args[0]));
int numPts = sc.nextInt();
Pt[] points = new Pt[numPts];
for (int i = 0; i < numPts; i++)
points[i] = new Pt(sc.nextInt(), sc.nextInt());
ArrayList<Pt> hull = grahamScan(points);
System.out.println("Graham Scan convex hull: ");
for (Pt p : hull)
System.out.println(" " + p);
:
}
Contest Algorithms:15. CG Topics
37
Input Data
hull3.txt
8
03
42
35
53
30
11
12
22
Contest Algorithms:15. CG Topics
38
Execution
> java ConvexHullTests hull3.txt
sorted pts: [(3.000, 0.000), (5.000, 3.000), (4.000, 2.000),
(3.000, 5.000), (2.000, 2.000), (1.000, 2.000), (0.000, 3.000),
(1.000, 1.000)]
Graham Scan convex hull:
(3.000, 0.000)
(5.000, 3.000)
(3.000, 5.000)
(0.000, 3.000)
(1.000, 1.000)
Contest Algorithms:15. CG Topics
a counter-clockwise
convex hull starting at the
lowest point
39
Stack Usage
p9
p11
p10
p6
p7
p8
p5
p2
p4
S
p
p3
2
p1
p1
p
0
p0
p9
p11
p10
p6
p7
p8
p5
p2
p4
S
p
p3
3
p1
p1
p
0
p0
p9
p11
p10
p6
p7
p8
p5
p2
p4
S
p
p3
4
p1
p1
p
0
p0
p9
p11
p10
p6
p7
p8
p5
p2
S
p4
p
5
p
p3
4
p1
p1
p
0
p0
p9
p11
p10
p6
p7
p8
p5
p2
S
p4
p6
p
p3
4
p1
p1
p
0
p0
S
p9
p11
p10
p7
p8
p8
p6
p5
p2
p4
p7
p6
p
p3
4
p1
p1
p
0
p0
S
p9
p11
p10
p6
p7
p8
p5
p2
p4
p7
p6
p
p3
4
p1
p1
p
0
p0
S
p9
p11
p10
p10
p6
p8
p4
p9
p7
p5
p2
p6
p
p3
4
p1
p1
p
0
p0
S
p9
p11
p10
p11
p6
p8
p4
p9
p7
p5
p2
p6
p
p3
4
p1
p1
p
0
p0
Finish
S
p9
p11
p10
p11
p6
p8
p4
p9
p7
p5
p2
p6
p
p3
4
p1
p1
p
0
p0
2.4. Jarvis’ March
A “package/gift wrapping” technique
O(n· h)
h is the no. of
vertices in the hull
(which might be n)
The Operation of Jarvis’ March
 set p = the leftmost point
 Repeat until p is again the leftmost point
 The next point q is chosen such that the triplet (p, q, r) is
counterclockwise for any other point r.
 Store q in the output convex hull
 set p = q
Code
see ConvexHullTexts.java
public static ArrayList<Pt> jarvisMarch(Pt[] pointsArr)
{
// pointsArr[numPts-1] is different from pointsArr[0]
ArrayList<Pt> pts = new ArrayList<Pt>(); // copy just in case
for (int i=0; i < pointsArr.length; i++)
pts.add(pointsArr[i]);
ArrayList<Pt> hull = new ArrayList<Pt>();
Pt leftPt = getLeftMost(pointsArr);
:
Contest Algorithms:15. CG Topics
52
//
//
Pt
Pt
do
Start from leftmost point, keep moving ccw (left)
until reach the start point again.
next = null;
prev = leftPt;
{ // O(h)
next = pts.get(0); // compare next with all other pts
for(int i = 1; i < pts.size(); i++) {
Pt cand = pts.get(i);
if ((Pt.ccw(prev, cand, next) > 0) ||
(Pt.ccw(prev, cand, next) == 0 &&
prev.dist(cand) > prev.dist(next)) ) {
next = cand; // cand is less left than next, so update next
}
}
hull.add(next);
pts.remove(next);
prev = next;
} while(next != leftPt);
return hull;
} // end of jarvisMarch()
Contest Algorithms:15. CG Topics
53
Execution
>
java ConvexHullTests hull3.txt
Javis March convex hull:
(1.000, 1.000)
(3.000, 0.000)
(5.000, 3.000)
(3.000, 5.000)
(0.000, 3.000)
same counter-clockwise
convex hull as Graham Scan,
but ending at the left-most point.
Contest Algorithms:15. CG Topics
54
Using Polygon.convexHull()
see ConvexHullTexts.java
Polygon p = new Polygon(points);
Polygon hullPoly = p.convexHull();
System.out.println("Polygon class' convex hull: " + hullPoly);
Contest Algorithms:15. CG Topics
55
 Polygon.convexHull() is a slightly different implementation
of the Graham Scan algorithm
 instead of using a stack, it employs ArrayList
 the lowest point is stored first in the hull, not last
 Graham Scan is faster than Jarvis March
 O(n log n) compared to O(n h)
 If the points are already sorted by one of the coordinates or by
the angle to a fixed vector, then the algorithm takes O(n) time
Contest Algorithms:15. CG Topics
56
3. Finding the Closest Pair of Points
 There are a set of n points P = { p1,…pn }.
 Find a pair of points p, q such that |p – q| is the minimum
of all |pi – pj|
 Easy to do in O(n2) time
 for all pi ≠ pj, compute ║pi - pj║ on all the pairs and choose the
minimum, which involves
n(n-1)/2 comparisons
 We will aim for O(n log n) time
Code
public static int[] bfClosestPair(Pt[] pts)
// brute-force version of the search = O(n^2)
{ int numPts = pts.length;
if (numPts < 2)
return null;
int[] pair = {0, 1}; // store indicies of pts
double minDist = pts[0].dist(pts[1]);
if (numPts > 2) {
for (int i = 0; i < numPts-1; i++) {
see ClosestPair.java
for (int j = i+1; j < numPts; j++) {
double dist = pts[i].dist(pts[j]);
if (dist < minDist) {
pair[0] = i; pair[1] = j;
minDist = dist;
}
}
}
}
return pair;
} // end of bfClosestPair()
Contest Algorithms:15. CG Topics
58
Usage
public static void main(String[] args) throws Exception
{
Scanner sc = new Scanner(new File("pointsData.txt"));
int numPts
Pt[] pts =
for (int i
pts[i] =
:
= sc.nextInt();
new Pt[numPts];
= 0; i < numPts; i++)
new Pt(sc.nextInt(), sc.nextInt());
// divide and conquer code, see later
int[] pair = bfClosestPair(pts);
Pt pt0 = pts[pair[0]];
Pt pt1 = pts[pair[1]];
System.out.println(" " + pt0 + " -- " + pt1 + ": " + pt0.dist(pt1));
} // end of main()
Contest Algorithms:15. CG Topics
59
Input Data
pointsData.txt
10
59
93
20
84
74
9 10
19
82
0 10
96
>
Contest Algorithms:15. CG Topics
java ClosestPair pointsData.txt
(7.000, 4.000) -- (8.000, 4.000): 1.0
60
Divide and Conquer
 Divide:
 Compute the median of the x-coordinates
 Split the points into a left half PL and right half PR, each of size n/2
median line
 Conquer: compute the closest pairs
for PL and PR
 Combine the results (the hard part)
PL
PR
public class ClosestPair
{
// closest pair of pts and their Euclidean distance
private Pt best1, best2;
private double bestDistance = Double.POSITIVE_INFINITY;
see ClosestPair.java
public ClosestPair(Pt[] pts)
{
int numPts = pts.length;
if (numPts < 2)
return;
// sort by x-coordinate (breaking ties by y-coordinate)
Pt[] ptsX = new Pt[numPts];
for (int i = 0; i < numPts; i++)
ptsX[i] = pts[i];
Arrays.sort(ptsX, new XOrder());
:
Contest Algorithms: 4. Backtracking
62
// check for coincident pts
for (int i = 0; i < numPts - 1; i++) {
if (ptsX[i].equals(ptsX[i + 1])) {
bestDistance = 0.0;
best1 = ptsX[i];
best2 = ptsX[i + 1];
return;
}
}
// sort by y-coordinate (but not yet sorted)
Pt[] ptsY = new Pt[numPts];
for (int i = 0; i < numPts; i++)
ptsY[i] = ptsX[i];
Pt[] aux = new Pt[numPts];
// auxiliary (temp) array
closest(ptsX, ptsY, aux, 0, numPts - 1);
} // end of ClosestPair()
Contest Algorithms:15. CG Topics
63
private double closest(Pt[] ptsX, Pt[] ptsY, Pt[] aux, int lo, int hi)
// find closest pair of pts in ptsX[lo..hi]
{
if (hi <= lo)
return Double.POSITIVE_INFINITY;
int mid = lo + (hi - lo) / 2;
Pt median = ptsX[mid];
// compute closest pair with both endpoints in left subarray
// or both in right subarray
double delta1 = closest(ptsX, ptsY, aux, lo, mid);
double delta2 = closest(ptsX, ptsY, aux, mid + 1, hi);
double delta = Math.min(delta1, delta2);
divide
conquer
combine
// merge back so that ptsY[lo..hi] are sorted by y-coordinate
ClosestPair.merge(ptsY, aux, lo, mid, hi);
// v.similar to merge in mergeSort
:
// more in a few slides
Contest Algorithms:15. CG Topics
64
Check y-strip?
median line
 Apart from the left and right halves
of the space, we must also check
pairs that cross the median line
less than d?
 Only interested in pairs within
distance < d of each other
 It's enough to look at only the
points in the 2d wide strip running
up the median line
PL
PR
median line
Scanning the Strip
d
 Sort all points in the strip by their
increasing y-coordinate values
 Examine each point moving up
the strip.
 Examine a point by considering
the d x 2d volume above it
 only points inside this volume need to
be considered
 there can only be a maximum of 7
points
d
d
How many points in the rectangle?
 Imagine that the rectangle is divided
into eight d/2 x d/2 squares
d/2
 Aside from the point we are looking
at, their can only be a maximum of
one point in each square
d/2
d/2
d/2
 This means our code need only look
at a maximum of 7 points above the
current point
Contest Algorithms:15. CG Topics
67
closest() Continued…
// aux[0..M-1] = sequence of pts closer than delta, sorted by y-coordinate
int M = 0;
for (int i = lo; i <= hi; i++) {
if (Math.abs(ptsY[i].x - median.x) < delta)
aux[M++] = ptsY[i];
}
// compare each point to its neighbors with y-coordinate closer than delta
for (int i = 0; i < M; i++) {
// a geometric packing argument shows that this loop iterates at most 7 times
for (int j = i + 1; (j < M) && (aux[j].y - aux[i].y < delta); j++) {
double distance = aux[i].dist(aux[j]);
if (distance < delta) {
delta = distance;
if (distance < bestDistance) {
bestDistance = delta;
This code does not have
best1 = aux[i];
best2 = aux[j];
running time O(n2) but O(n∙7)
}
}
}
}
return delta;
== O(n)
}
Contest Algorithms:15. CG Topics
68
Running time
the two recursive
calls to closest()

the examination
of the strip
T(n) = 2* T(n/2) + O(n)
 the same as Mergesort, which is O(n log n)
Contest Algorithms:15. CG Topics
69
Other methods in ClosestPair class
// globals in ClosestPair class
private Pt best1, best2;
private double bestDistance = Double.POSITIVE_INFINITY;
public Pt either()
{ return best1; }
public Pt other()
{ return best2; }
public double distance()
{ return bestDistance; }
Contest Algorithms:15. CG Topics
70
Usage
see ClosestPair.java
ClosestPair closest = new ClosestPair(pts);
System.out.println(" " + closest.either() + " -- " +
closest.other() + ": " + closest.distance());
Contest Algorithms:15. CG Topics
71