凸包是正好包含所有點的凸邊形,之所以叫凸包,是因為凸中包含了凸多邊形包圍起來的所有點
我們要寫的是找出凸包的頂點集,使用分治演算法
首先,連線最左端和最右端的兩點。命名線上方的區域為上包,下方位下包,將兩點加入到頂點集合
然後,找到與直線距離最遠的兩點,與第一步中的兩點相連,劃分為上包和下包,新找出的兩點為新的頂點加入到頂點集合
在此之後,上包遞迴分為上下兩個子包,下包地櫃分為兩個子包,知道包節點數小於等於1,每次遞迴都要將新的頂點加入到頂點集。
分治的思路是每一次遞迴找到乙個頂點,把剩餘的頂點交給子問題,有子包去解決
from math import sqrt
solution = # 頂點集
def convex_hull(points):
# 凸包演算法
# 長度小於=3 三角形
if len(points) <= 3:
return points
# 宣告全域性變數
global solution
# x座標排序
points.sort(key=lambda x: x[0])
# 左邊最遠值
left_most = points[0]
# 右邊最遠值
right_most = points[- 1]
# 將左邊右邊最遠值分別加入到頂點集合的後面 extend拆分新增
solution.extend([left_most, right_most])
# 分治 true為上包 false為下包
helper(points, left_most, right_most, true)
helper(points, left_most, right_most, false)
return solution
def helper(points, left_most, right_most, upbool):
"""利用line_helper計算left_most, right_most的最短距離
計算點集合中每個點到直線的距離
上包,將距離大於0的加入到新集合,找出最遠值
下包,將距離小於0的加入到新集合,找出最遠值
再次呼叫helper方法 傳入新的集合和最遠值
:param points: 點集合
:param left_most: 左邊最遠值
:param right_most: 右邊最遠值
:param upbool: true為上包 false為下包
:return:
"""global solution
# 點集合為0或者1的時候 不需要計算
if len(points) <= 1:
return
# 利用line_helper計算left_most, right_most的最短距離
l = line_helper(left_most, right_most)
# 上包
if upbool:
# 新集合
up =
# 新的點到直線的距離
max_distance = 0
# 最遠點
max_point = ()
for point in points:
# 計算點到直線的距離
distance = 0 - (l[0] * point[0] + l[1] * point[1] + l[2]) / sqrt(l[0] * l[0] + l[1] * l[1])
if distance > 0:
# 將距離大於0的加入到新集合
if distance > max_distance:
max_distance = distance
max_point = point
# 存在最遠值
if max_point != ():
# 最遠值加入到頂點集合
# 再次呼叫helper方法 傳入新的集合和最遠值
helper(up, left_most, max_point, true)
helper(up, max_point, right_most, true)
else:
# 下包
down =
min_distance = 0
min_point = ()
for point in points:
distance = 0 - (l[0] * point[0] + l[1] * point[1] + l[2]) / sqrt(l[0] * l[0] + l[1] * l[1])
if distance < 0:
if distance < min_distance:
min_distance = distance
min_point = point
if min_point != ():
helper(down, left_most, min_point, true)
helper(down, min_point, right_most, true)
def line_helper(point1, point2):
# 傳入兩點
if point1[0]-point2[0] != 0: # 不是豎線
m = (point1[1]-point2[1]) / (point1[0]-point2[0])
c = point1[1]-m*point1[0]
return [m, -1, c]
else:
return [1, 0, point1[0]]
if __name__ == '__main__':
inp = [(0,0), (0,4), (-4, 0), (5, 0), (0, -6), (1, 0)]
# out = [(-4, 0), (5, 0), (0, -6), (0, 4)]
print(convex_hull(inp))
凸包問題 (用分治演算法)
問題描述 在平面上有n個點,其中任何三個點都不在一條直線上,問如何尋找乙個點集,使得這些點構成的多邊形剛好能把所有點都包進。基本思想 我們採用分治演算法。首先算出這n個點的橫座標中位數,記為x0,畫出直線x x0,將整個平面分成兩部分。我們要做的就是分別求兩部分的凸包,最後再合併即可。利用分治和遞迴...
分治法 凸包問題
什麼是凸包?我的理解就是,圖形任意兩點的連線都沒有在圖形外部。問題 給定點集,怎麼求出凸包的邊界點呢?第一步 給這些點按照x的從大到小進行排序,如果x相同的按照y再排序。第二步 把x最小的和最大的連起來,他們必為凸包的邊界點。第三步 把平面區域分為兩個部分,分別在上面和下面去找面積最大的三角形 面積...
凸包問題之分治法
凸包 按橫座標排序,以最小點與最大點之間的連線為準,在直線一側找使三角形面積最大的點,此點必在凸包內,以找到點與最大點或最小點繼續遞迴以尋找最大三角形面積尋找凸包點,直至找不到符合條件的點。實現 如下 include include include define max size 10001 str...