Divide and conquer solution idea

1. Find the line formed by the two points P1 and P2 with the largest and smallest abscissa. The line is used to divide the set of points into two set1 and set2 parts.

Division of the upper half:

2. Find points P3 and P4 of the triangle with the largest area formed by line segment P1P2 from set1 and set2 respectively.

3. From set1, find the point set LeftSet1 on the left side of P1P3 and RightSet1 on the right side of P3P2.

4. LeftSet1, LeftSet2 and repeat steps 2 and 3 until no point more outside the line can be found.

Division of the Lower Half:

5. From set2, find the point set leftSet2 on the left side of P1P4 and the point set rightSet2 on the right side of P3P4.

6. Repeat steps 2 and 3, LeftSet1 and LeftSet2, until no point more outside the line can be found.

Merger:

Well, the answer was already generated before the merger, but I don’t need the set of answer points, so let’s make it clockwise

Point and line position judgment

The position relationship between the line and the point can be determined by the positive and negative values of the following determinant, and the value is the area of the triangle enclosed by the point and the line segment:

The following drawing process dynamic diagram, you can deepen the understanding. The idea is to recursively divide the whole into two halves, recursively find a point in each half to maximize the area of the triangle formed by the dividing line, until no point can be found outside the dividing line of the half region to form a triangle, then the half region stops and goes back to the upper half to continue processing…

code

import random import matplotlib.pyplot as plt import matplotlib.animation as animation draw_line_lists = [] # Calculate the triangle area def calc_area(a, b, c) according to the coordinates of the three vertices: Return x1 * y2 + x3 * y3 * y3-x3 * y2-x2 * y1-x1 * y3 # Return list [(x1,y1)...(xn,yn)]) def sample(n, start=0, end=101): return list(zip([random.randint(start, end) for _ in range(n)], [random.randint(start, End) for _ in range(n)])) def Up(left, right, points, borders): "" Tuple, rightmost point :param points: set of all points: param borders: set of points: return: Draw_line_lists.append (left) draw_line_lists.append(right) # left and right_point For item in points: if item == left or item == right: if item == left or item == right # The list of two points in a line is also in the list set, but it is not above the line. If temp = calc_area(left, right, item) AREA_MAX = TEMP # AREA_MAX = TEMP # AREA_MAX = TEMP = 0: # This is the recursive boundary. When there is no longer any temptation at the top of a line, it stops, returns to the next level, and processes the subtrees of its sibling nodes. Border. append(max_point) Up(left, max_point, points, borders) # border. append(max_point) Up(left, max_point, points, borders) # Continue recursion Up(max_point, right, points, borders) # The original right boundary point remains the same, and take the newly found point that forms the maximum triangle as the left boundary point. Continue recursive def Down(left, right, points, borders): Draw_line_lists.append (left) draw_line_lists.append(right) # left and right_point For item in points: if item == left or item == right: if item == left or item == right: # The list of two points in a line is also in the list set, but it is not below the line. If temp = calc_area(left, right, item) AREA_MAX = TEMP # AREA_MAX = TEMP # AREA_MAX = TEMP = 0: # This is the recursive boundary. When there is no longer any temptation under a line, it stops, returns to the next level, and processes the subtrees of its sibling nodes. Border. append(max_point) Down(left, max_point, points, borders) # Borders. Append (max_point) Down(left, max_point, points, borders) # Borders. Continue to recurse Down(max_point, right, points, borders) # The original right boundary point remains unchanged. Take the newly found point that forms the maximum triangle as the left boundary point and continue to recurse # Merging step. Def order_border(points) def order_border(points): """ :param points: unordered set of points: return: List [(,)... (and)] "" "points. The sort () # in x axis order row first, First_y = points[0] first_y = points[0] first_y = points[0] Last_y = points[-1] # up_borders =[] # dowm_borders =[] # dowm_borders =[] # x, y = item if y > max(first_y, last_y): Up_border. append(item) elif min(first_y, last_y) < y < Max (first_y, last_y): # If it is midway between the leftmost point and the rightmost point, use the area of the triangle. If the area is negative, it is an inverted triangle, meaning that the third point is below the line, the lower half; If calc_area(points[0], points[-1], item) > 0: up_border.append (item) else: dowm_border.append (item) else: dowm_border.append (item) else: # If y is smaller than both the leftmost and rightmost points, Dowm_border. append(item) list_end = up_borders + dowm_borders[::-1] return list_end def Draws (points, list_frames, gif_name="save.gif"): "" Draws (points, list_frames, gif_name="save.gif"): "" Save :param points: all points: param list_frames: Return:.gif """ min_value = 0 max_value = 100 all_x = [] all_y = [] for item in points: A, b = item all_x.append(a) all_y. Append (b) Fig, Ax = plt.subplots() # to generate axons and Fig, Iterable objects x, y = [], [] # to be used for the updated data line after receiving = plt.plot([], [], color="red") # Plot ([], [], color="red") Ax. Set_xlim (min_value -abs (min_value * 0.1), max_value + abs(max_value * 0.1)) Ax.set_ylim (min_value -abs (min_value * 0.1), max_value + abs(max_value * 0.1)) return line def update(points): a, b = points x.append(a) y.append(b) line.set_data(x, y) return line plt.scatter(all_x, ANI = animation.funcanimation (Fig., update, frames=list_frames, init_func=init, update, frames=list_frames ANI. Save (gif_name, writer='pillow') def show_result(points, results): "" Drawing :param points: all points: param results: all edges :return: picture """ all_x = [] all_y = [] for item in points: a, b = item all_x.append(a) all_y.append(b) for i in range(len(results)-1): Item_1 =results[I] item_2 =results[I +1] # Item_, oneI = item_1 two_, twoI = item_2 plt.plot([one_, two_], [oneI, twoI]) plt.scatter(all_x, all_y) plt.show() if __name__ == "__main__": points = [(101, 47), (32, 40), (21, 90), (65, 100), (98, 64), (81, 43), (51, 20), (75, 82), (90, 34), (38, 101) # points = sample(100) # points = sample(100) # points = sample(100) Borders = [] # Up(points[0], points[-1], points, borders) # Down(points[0], points[-1], points[-1], points[-1]) points, Border. append(points[0]) border. append(points[-1]) # Results = order_border(borders) # Print (results) # print(results [0]) # print(results [0]) # print(results [0]) # # draw closed lines (points,results only) # draw static results (points,results, "result.gif") # draw dynamic results (points, Draws ws(points, results, "result.gif") Draw_line_lists, "process.gif"

Program run result

Input coordinate point

[(101, 47), (32, 40), (21, 90), (65, 100), (98, 64), (43), 81, (51, 20), (75, 82), (90, 34) and (38, 101)]

Output dynamic drawing process

Output join point order

[(38, 101), (65, 100), (98, 64), (101, 47), (90, 34), (51, 20), (32, 40), (21, 90)]

Statically output the maximum convex polygon

Dynamically output the maximum convex polygon