You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二维最小面积凸k边形算法实现异常求助

求点集最小面积凸k边形的算法实现问题

我正在解决的问题:给定点集P与数值k,求由P的k点子集S构成的最小面积凸k边形的面积(其中|P|=n,|S|=k)。

我找到一篇论文,其描述的算法可在O(kn³)复杂度下解决该问题(符合我k值较大的场景需求),具体算法见第4节(Algorithm 3)。基于该论文,我实现了如下Python脚本:

import math
import numpy as np
from scipy.spatial import ConvexHull

# 判断点p在直线ab的哪一侧:+1为左侧,0为共线,-1为右侧
def side(a, b, p):
    t = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0])
    return math.copysign(1, t)

def angle(v1, v2):
    v1_u = v1 / np.linalg.norm(v1)
    v2_u = v2 / np.linalg.norm(v2)
    return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))

# 计算三角形abc的面积
def area(a, b, c):
    return abs(ConvexHull([a,b,c]).volume)

# 计算直线ab的斜率
def slope(a, b):
    return (b[1] - a[1]) / (b[0] - a[0])

# 返回P中位于pi上方、围绕pi顺时针排序的点列表
def get_above_clockwise(pi, P, ref = np.array((-1, 0))):
    above = [p for p in P if p[1] > pi[1]]
    return sorted(above, key=lambda x: angle(ref, np.array(x) - np.array(pi)))

# 返回围绕pj按斜率顺时针排序的P中点列表(排除pj自身)
def get_slope_clockwise(pj, P):
    T = [p for p in P if p != pj]
    return sorted(T, key=lambda x: abs(slope(pj, x)))

def get_min_kgon(P, K):
    D = {p:i for i, p in enumerate(P)}
    T = np.full((K+1, len(P), len(P), len(P)), np.inf, dtype=np.float32)

    total_min = np.inf

    for pi in P:
        T[2, D[pi]].flat = 0
        PA = get_above_clockwise(pi, P)
        for k in range(3, K+1):
            for pj in PA:
                min_area = np.inf
                
                PA2 = get_slope_clockwise(pj, PA + [pi])
                pi_idx = PA2.index(pi)
                PA2 = PA2[(pi_idx+1):] + PA2[:pi_idx]
        
                for pl in PA2:
                    if pl == pj: continue
                    if side(pi, pj, pl) == 1:
                        min_area = min(min_area, T[k-1, D[pi], D[pl], D[pj]] + area(pi, pj, pl))
                    T[k, D[pi], D[pj], D[pl]] = min_area
        
        total_min = min(total_min, np.min(T[K, D[pi]].flat))

    return total_min

我还实现了暴力求解函数以验证结果:

from itertools import combinations
from scipy.spatial import ConvexHull

def reliable_min_kgon(P, K):
    m = np.inf
    r = None
    for lst in combinations(P, K):
        ch = ConvexHull(lst)
        if ch.volume < m and len(ch.vertices) == K:
            m = ch.volume
            r = lst
    return m, r

目前我已卡壳数日,代码结果时而正确时而错误,我猜测是围绕pj排序点pl的逻辑存在问题,恳请有计算几何经验或了解该论文/问题的人士提供帮助。

提供一组测试用例,其中get_min_kgon(P,k) != reliable_min_kgon(P, k):

K = 5
P = [
(102, 466), (435, 214), (860, 330), (270, 458), (106, 87),
(71, 372), (700, 99), (20, 871), (614, 663), (121, 130)
]

点集P可视化

注:输入点集处于一般位置,且仅包含整数坐标。

内容的提问来源于stack exchange,提问作者Toby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:27:33