Eod.
This commit is contained in:
74
tsp/geometry.py
Normal file
74
tsp/geometry.py
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
def on_segment(p, q, r):
|
||||
# Given three colinear points p, q, r, the function checks if
|
||||
# point q lies on line segment 'pr'
|
||||
if q.x <= max(p.x, r.x) and q.x >= min(p.x, r.x) and \
|
||||
q.y <= max(p.y, r.y) and q.y >= min(p.y, r.y):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def orientation(p, q, r):
|
||||
# To find orientation of ordered triplet (p, q, r).
|
||||
# The function returns following values
|
||||
# 0 --> p, q and r are colinear
|
||||
# 1 --> Clockwise
|
||||
# 2 --> Counterclockwise
|
||||
|
||||
# See https://www.geeksforgeeks.org/orientation-3-ordered-points/
|
||||
# for details of below formula.
|
||||
val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y)
|
||||
|
||||
if val == 0:
|
||||
return 0 # colinear
|
||||
|
||||
# clock or counterclock wise
|
||||
if val > 0:
|
||||
return 1
|
||||
return 2
|
||||
|
||||
|
||||
def in_square(p1, x_min, x_max, y_min, y_max):
|
||||
if p1.x < x_min or p1.x > x_max:
|
||||
return False
|
||||
if p1.y < y_min or p1.y > y_max:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def in_circle(p1, p_center, radius):
|
||||
return (p1.x - p_center.x)**2 + (p1.y - p_center.y)**2 < radius**2
|
||||
|
||||
|
||||
def do_intersect(p1, q1, p2, q2):
|
||||
# The main function that returns true if line segment 'p1q1'
|
||||
# and 'p2q2' intersect.
|
||||
# Find the four orientations needed for general and
|
||||
# special cases
|
||||
o1 = orientation(p1, q1, p2)
|
||||
o2 = orientation(p1, q1, q2)
|
||||
o3 = orientation(p2, q2, p1)
|
||||
o4 = orientation(p2, q2, q1)
|
||||
|
||||
# General case
|
||||
if (o1 != o2 and o3 != o4):
|
||||
return True
|
||||
|
||||
# Special Cases
|
||||
# p1, q1 and p2 are colinear and p2 lies on segment p1q1
|
||||
if (o1 == 0 and on_segment(p1, p2, q1)):
|
||||
return True
|
||||
|
||||
# p1, q1 and q2 are colinear and q2 lies on segment p1q1
|
||||
if (o2 == 0 and on_segment(p1, q2, q1)):
|
||||
return True
|
||||
|
||||
# p2, q2 and p1 are colinear and p1 lies on segment p2q2
|
||||
if (o3 == 0 and on_segment(p2, p1, q2)):
|
||||
return True
|
||||
|
||||
# p2, q2 and q1 are colinear and q1 lies on segment p2q2
|
||||
if (o4 == 0 and on_segment(p2, q1, q2)):
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -1,45 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import math
|
||||
from collections import namedtuple
|
||||
|
||||
Point = namedtuple("Point", ['x', 'y'])
|
||||
|
||||
def length(point1, point2):
|
||||
return math.sqrt((point1.x - point2.x)**2 + (point1.y - point2.y)**2)
|
||||
|
||||
def solve_it(input_data):
|
||||
# Modify this code to run your optimization algorithm
|
||||
|
||||
# parse the input
|
||||
lines = input_data.split('\n')
|
||||
|
||||
nodeCount = int(lines[0])
|
||||
|
||||
points = []
|
||||
for i in range(1, nodeCount+1):
|
||||
line = lines[i]
|
||||
parts = line.split()
|
||||
points.append(Point(float(parts[0]), float(parts[1])))
|
||||
|
||||
# build a trivial solution
|
||||
# visit the nodes in the order they appear in the file
|
||||
solution = range(0, nodeCount)
|
||||
|
||||
# calculate the length of the tour
|
||||
obj = length(points[solution[-1]], points[solution[0]])
|
||||
for index in range(0, nodeCount-1):
|
||||
obj += length(points[solution[index]], points[solution[index+1]])
|
||||
|
||||
# prepare the solution in the specified output format
|
||||
output_data = '%.2f' % obj + ' ' + str(0) + '\n'
|
||||
output_data += ' '.join(map(str, solution))
|
||||
|
||||
return output_data
|
||||
|
||||
|
||||
import sys
|
||||
from tsp import solve_it
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
175
tsp/tsp.py
Normal file
175
tsp/tsp.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import math
|
||||
from functools import lru_cache
|
||||
from collections import namedtuple
|
||||
from geometry import do_intersect
|
||||
|
||||
Point = namedtuple("Point", ['index', 'x', 'y'])
|
||||
|
||||
|
||||
def parse_input_data(input_data):
|
||||
lines = input_data.split('\n')
|
||||
node_count = int(lines[0])
|
||||
return [Point(i, *map(float, lines[i].split()))
|
||||
for i in range(1, node_count + 1)]
|
||||
|
||||
|
||||
def plot_solution(solution, points):
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def plot_arrows():
|
||||
for i in range(len(solution)):
|
||||
p_1_index = solution[i - 1]
|
||||
p_2_index = solution[i]
|
||||
plot_arrow(p_1_index, p_2_index)
|
||||
|
||||
def plot_arrow(p_1_index, p_2_index):
|
||||
p_1 = points[p_1_index]
|
||||
p_2 = points[p_2_index]
|
||||
x = p_1.x
|
||||
y = p_1.y
|
||||
dx = p_2.x - x
|
||||
dy = p_2.y - y
|
||||
plt.arrow(x, y, dx, dy,
|
||||
head_width=0.5, head_length=0.5)
|
||||
|
||||
def plot_points():
|
||||
for i, p in enumerate(points):
|
||||
plt.plot(p.x, p.y, '')
|
||||
plt.text(p.x, p.y, ' ' + str(i))
|
||||
|
||||
plot_points()
|
||||
plot_arrows()
|
||||
plt.show()
|
||||
|
||||
|
||||
def solve_it(input_data):
|
||||
|
||||
@lru_cache(maxsize=1000000)
|
||||
def length(point_1_index, point_2_index):
|
||||
p_1 = points[point_1_index]
|
||||
p_2 = points[point_2_index]
|
||||
return math.sqrt((p_1.x - p_2.x)**2 + (p_1.y - p_2.y)**2)
|
||||
|
||||
def prepare_output_data(solution):
|
||||
obj = calculate_length(solution)
|
||||
output_data = '%.2f' % obj + ' ' + str(0) + '\n'
|
||||
output_data += ' '.join(map(str, solution))
|
||||
return output_data
|
||||
|
||||
def is_valid(solution):
|
||||
points = set(range(len(solution)))
|
||||
assert(set(solution) == points)
|
||||
return True
|
||||
|
||||
def calculate_length(solution):
|
||||
obj = 0
|
||||
for i in range(0, len(solution)):
|
||||
point_1_index = solution[i - 1]
|
||||
point_2_index = solution[i]
|
||||
obj += length(point_1_index, point_2_index)
|
||||
return obj
|
||||
|
||||
def initial_solution_naiv():
|
||||
return list(range(0, node_count))
|
||||
|
||||
def does_edge_cause_intersection(edge, edges):
|
||||
p1 = points[edge[0]]
|
||||
p2 = points[edge[1]]
|
||||
|
||||
for existing_edge in edges:
|
||||
q1 = points[existing_edge[0]]
|
||||
q2 = points[existing_edge[1]]
|
||||
print(p1, p2, q1, q2)
|
||||
if do_intersect(p1, q1, p2, q2):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_dimensions(point_indices):
|
||||
p = points[0]
|
||||
x_min_p = p
|
||||
x_max_p = p
|
||||
y_min_p = p
|
||||
y_max_p = p
|
||||
|
||||
x_min = p.x
|
||||
x_max = p.x
|
||||
y_min = p.y
|
||||
y_max = p.y
|
||||
|
||||
for p in points:
|
||||
if p.x < x_min:
|
||||
x_min = p.x
|
||||
x_min_p = p
|
||||
if p.y < y_min:
|
||||
y_min = p.y
|
||||
y_min_p = p
|
||||
if p.x > x_max:
|
||||
x_max = p.x
|
||||
x_max_p = p
|
||||
if p.y > y_max:
|
||||
y_max = p.y
|
||||
y_max_p = p
|
||||
|
||||
return (x_min_p, x_max_p, y_min_p, y_max_p)
|
||||
|
||||
def initial_solution_greedy(point_indices):
|
||||
current_point = get_dimensions(point_indices)[0].index
|
||||
xs = [current_point]
|
||||
points = set(point_indices)
|
||||
points.remove(current_point)
|
||||
|
||||
while points:
|
||||
min_length = 999999
|
||||
min_point = None
|
||||
for next_point in points:
|
||||
new_length = length(current_point, next_point)
|
||||
if new_length < min_length:
|
||||
min_length = new_length
|
||||
min_point = next_point
|
||||
xs.append(min_point)
|
||||
points.remove(min_point)
|
||||
current_point = min_point
|
||||
|
||||
return xs
|
||||
|
||||
def local_search(solution):
|
||||
# Find longest edges to swap
|
||||
max_len_1 = 0
|
||||
max_len_2 = 0
|
||||
edge_1 = None
|
||||
edge_2 = None
|
||||
|
||||
for i in range(node_count):
|
||||
new_len = length(solution[i - 1], solution[i])
|
||||
if new_len > max_len_1:
|
||||
max_len_1 = new_len
|
||||
edge_1 = (i - 1, i)
|
||||
|
||||
for i in range(node_count):
|
||||
new_len = length(solution[i - 1], solution[i])
|
||||
if new_len > max_len_2 and new_len != max_len_1:
|
||||
max_len_2 = new_len
|
||||
edge_2 = (i - 1, i)
|
||||
|
||||
a_1, a_2 = edge_1
|
||||
print(edge_1, edge_2)
|
||||
n_a_1, n_a_2 = [solution[a_1], solution[a_2]]
|
||||
print(n_a_1, n_a_2)
|
||||
b_1, b_2 = edge_2
|
||||
n_b_1, n_b_2 = [solution[b_1], solution[b_2]]
|
||||
print(n_b_1, n_b_2)
|
||||
|
||||
solution[a_2] = n_b_2
|
||||
solution[b_2] = n_a_2
|
||||
|
||||
return solution
|
||||
|
||||
points = parse_input_data(input_data)
|
||||
node_count = len(points)
|
||||
solution = initial_solution_greedy(list(range(node_count)))
|
||||
local_search(solution)
|
||||
# solution = initial_solution_naiv()
|
||||
|
||||
plot_solution(solution, points)
|
||||
is_valid(solution)
|
||||
return prepare_output_data(solution)
|
||||
Reference in New Issue
Block a user