Last active
March 21, 2018 08:39
-
-
Save qwert2603/0d3d635d21a25630b81dec302bdc8c19 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedReader; | |
import java.io.InputStreamReader; | |
import java.util.*; | |
public class Main { | |
public static final class Point implements Comparable<Point> { | |
final int x; | |
final int y; | |
private final int pos; | |
public Point(final int x, final int y) { | |
this.x = x; | |
this.y = y; | |
pos = (x << 14) + y; | |
} | |
@Override | |
public int compareTo(final Point o) { | |
return Integer.compare(pos, o.pos); | |
} | |
} | |
public static boolean isInside(final Point p1, final Point p2, final Point point) { | |
return (p2.y - p1.y) * (point.x - p1.x) <= (p2.x - p1.x) * (point.y - p1.y); | |
} | |
// 0 - on line, 1 - upper, -1 - below. | |
public static int isUpperBelow(final Point left, final Point right, final Point center) { | |
if (left.y == right.y) return Integer.compare(center.y, left.y); | |
int A = right.y - left.y; | |
int B = right.x - left.x; | |
int x = center.x - left.x; | |
int y = center.y - left.y; | |
return Integer.compare(0, A * x - B * y); | |
} | |
// points must be sorted by X (else Y). | |
private static Point[] skinThem(final Point[] points) { | |
final boolean[] border = new boolean[points.length]; | |
border[0] = true; | |
border[points.length - 1] = true; | |
int borderPointsCount = 0; | |
int[] upperBelow = new int[points.length]; | |
upperBelow[0] = 1; | |
upperBelow[points.length - 1] = -1; | |
for (int i = 1; i < points.length - 1; i++) { | |
upperBelow[i] = isUpperBelow(points[0], points[points.length - 1], points[i]); | |
} | |
final int[] stack = new int[points.length]; | |
// bottom border | |
int head = 0; | |
stack[0] = 0; | |
stack[1] = -1; | |
for (int i = 1; i < points.length - 1; i++) { | |
if (upperBelow[i] == -1) { | |
stack[1] = i; | |
++head; | |
break; | |
} | |
} | |
if (stack[1] != -1) { | |
for (int i = stack[1] + 1; i <= points.length - 1; i++) { | |
if (upperBelow[i] != -1) continue; | |
while (head >= 1 && isInside(points[stack[head - 1]], points[i], points[stack[head]])) { | |
--head; | |
} | |
++head; | |
stack[head] = i; | |
} | |
borderPointsCount += head; | |
} else { | |
++borderPointsCount; | |
} | |
for (int i = 0; i <= head; i++) { | |
border[stack[i]] = true; | |
} | |
// top border | |
head = 0; | |
stack[0] = points.length - 1; | |
stack[1] = -1; | |
for (int i = points.length - 2; i >= 0; i--) { | |
if (upperBelow[i] == 1) { | |
stack[1] = i; | |
++head; | |
break; | |
} | |
} | |
if (stack[1] != -1) { | |
for (int i = stack[1] - 1; i >= 0; i--) { | |
if (upperBelow[i] != 1) continue; | |
while (head >= 1 && isInside(points[stack[head - 1]], points[i], points[stack[head]])) { | |
--head; | |
} | |
++head; | |
stack[head] = i; | |
} | |
borderPointsCount += head; | |
} else { | |
++borderPointsCount; | |
} | |
for (int i = 0; i <= head; i++) { | |
border[stack[i]] = true; | |
} | |
Point[] insiders = new Point[points.length - borderPointsCount]; | |
int nextInsider = 0; | |
for (int i = 1; i < points.length - 1; i++) { | |
if (!border[i]) insiders[nextInsider++] = points[i]; | |
} | |
return insiders; | |
} | |
public static boolean isOneLine(final Point[] points) { | |
final int dx = points[1].x - points[0].x; | |
final int dy = points[1].y - points[0].y; | |
for (int i = 2; i < points.length; i++) { | |
int dxi = points[i].x - points[0].x; | |
int dyi = points[i].y - points[0].y; | |
if (dxi * dy != dx * dyi) { | |
return false; | |
} | |
} | |
return true; | |
} | |
public static int bordersCount(Point[] points) { | |
Arrays.sort(points); | |
int count = 0; | |
while (points.length >= 3 && !isOneLine(points)) { | |
points = skinThem(points); | |
++count; | |
} | |
return count; | |
} | |
public static void main(String[] args) throws Exception { | |
final BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | |
final int N = Integer.parseInt(br.readLine()); | |
final Point[] points = new Point[N]; | |
for (int i = 0; i < N; i++) { | |
String[] split = br.readLine().split(" "); | |
final int x = Integer.parseInt(split[0]); | |
final int y = Integer.parseInt(split[1]); | |
points[i] = new Point(x, y); | |
} | |
System.out.println(bordersCount(points)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment