Reputation: 8058
Firstly, I'm not asking for code, I just want clarification about my approach.
Secondly, if this isn't totally SO related, I will move the question to the most relevant Stack Exchange site. I'm pretty sure this is a graph theory related problem.
So I have an infinitely large grid with a defined point (0,0)
Each intersection between horizontal/vertical lines in the grid defines another point (given by the number of lines from the origin).
Given a set of points (x,y)
where each x,y
is an Integer: return the perimeter of the smallest polygon surrounding the points.
Constraints:
My guess that the is a Graph Theory related problem. Just like the Travelling Salesman, I first need to find the shortest path between all points using an algorithm which gives an optimal solution. Then I need to perform the same algorithm between each point to find the optimal path along the grid between the points.
I have written an algorithm for the Travelling Salesman given 80 towns.
In this question there can be 100,000 points. So that makes me wonder if a possible algorithm even exists to solve such a huge number of Nodes.
Is there another approach. Am I thinking about this the wrong way?
Thanks for any help!
Upvotes: 8
Views: 2979
Reputation:
The Convex hull
is not actually necessary to solve this problem.
The most time efficient convex hull
algorithm is O(nlogh)
, where n
is the number of points overall, and h
is the number of points on the hull.
Looking through the comments above, m69
nailed it! The algorithm he describes (with a bit extra on top) can be achieved in O(n)
time. Scrap the Convex Hull
idea!!
O(n)
Here is my version of the algorithm (written in python). People are free to comment or optimise it if they wish. It was a fun problem to solve.
from math import *
N = int(raw_input())
pts = []
for i in xrange(N):
p1,p2 = map(int, raw_input().split(' '))
pts.append((p1,p2))
def isBetween(a, b, c):
ab = sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
ac = sqrt((a[0]-c[0])**2 + (a[1]-c[1])**2)
bc = sqrt((b[0]-c[0])**2 + (b[1]-c[1])**2)
return abs(ac + bc - ab) < 0.01 # epsilon precision, needs < 1 in grid case
def getPoints(c):
lines = [(-1, c[0][1]+c[0][0]),(1, c[1][1]-c[1][0]),(-1,c[2][1]+c[2][0]),(1,c[3][1]-c[3][0])]
maxes = [[0,0],[0,0],[0,0],[0,0]]
for count, line in enumerate(lines):
pdist = (abs(line[0]*CH[0][0] - CH[0][1] + line[1]))/(sqrt((line[0]*line[0]) + 1 ))
maxes[count][0] = pdist
maxes[count][1] = CH[0]
for elem in CH[1:]:
for count, line in enumerate(lines):
pdist = (abs(line[0]*elem[0] - elem[1] + line[1]))/(sqrt((line[0]*line[0]) + 1 ))
if pdist < maxes[count][0]:
maxes[count][0] = pdist
maxes[count][1] = elem
for greg in range(4):
maxes[greg][1] = list(maxes[greg][1])
maxes[0][1][0] -=1
maxes[1][1][0] +=1
maxes[2][1][0] +=1
maxes[3][1][0] -=1
gregarr = []
for i in range(4):
y = lines[i][0]*(c[i][0]-maxes[i][1][0]) + maxes[i][1][1]
cornerdist = abs(c[i][1] - y)
if i == 0:
gregarr.append((c[i][0], c[i][1]+cornerdist))
gregarr.append((c[i][0]+cornerdist, c[i][1]))
elif i == 1:
gregarr.append((c[i][0]-cornerdist, c[i][1]))
gregarr.append((c[i][0], c[i][1]+cornerdist))
elif i == 2:
gregarr.append((c[i][0], c[i][1]-cornerdist))
gregarr.append((c[i][0]-cornerdist, c[i][1]))
else:
gregarr.append((c[i][0]+cornerdist, c[i][1]))
gregarr.append((c[i][0], c[i][1]-cornerdist))
return gregarr
def distance(p0, p1):
return ((p0[0] - p1[0])*(p0[0] - p1[0]) + (p0[1] - p1[1])*(p0[1] - p1[1]))**(0.5)
def f7(seq):
seen = set()
seen_add = seen.add
return [ x for x in seq if not (x in seen or seen_add(x))]
CH = pts
H = len(CH)
if H == 0:
print('0.000')
elif H == 1:
print('5.656')
else:
per = 0
minx = min(CH, key = lambda x: x[0])[0]-1
miny = min(CH, key = lambda x: x[1])[1]-1
maxx = max(CH, key = lambda x: x[0])[0]+1
maxy = max(CH, key = lambda x: x[1])[1]+1
corners = [(minx,miny),(maxx, miny),(maxx,maxy),(minx,maxy)]
arr = getPoints(corners)
arr = f7(arr)
arr.append(arr[0])
T = len(arr)
for i in range(1,T):
per += distance(arr[i-1], arr[i])
print(per)
Upvotes: 1