Skip to content

Instantly share code, notes, and snippets.

@qwert2603
Last active March 21, 2018 08:39
Show Gist options
  • Save qwert2603/0d3d635d21a25630b81dec302bdc8c19 to your computer and use it in GitHub Desktop.
Save qwert2603/0d3d635d21a25630b81dec302bdc8c19 to your computer and use it in GitHub Desktop.
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