# 查找一组2D点的凸包

20

• 作为函数编写，该点的列表坐标（任意格式）是参数
• 输出必须是顺时针或逆时针列出的凸包中的点列表，从任何一个开始
• 输出列表可以采用任何合理的格式，其中每个点的坐标都可以清楚地区分。（例如，不是一个模糊列表{0.1、1.3、4，...}）
• 如果凸包的一段中的三个或更多点对齐，则输出中仅应保留两个极端

### 样品0

``````{{1, 1}, {2, 2}, {3, 3}, {1, 3}}
``````

``````{{3, 3}, {1, 3}, {1, 1}}
``````

（这些数字只是说明性的）

### 样品1

``````{{4.4, 14}, {6.7, 15.25}, {6.9, 12.8}, {2.1, 11.1}, {9.5, 14.9},
{13.2, 11.9}, {10.3, 12.3}, {6.8, 9.5}, {3.3, 7.7}, {0.6, 5.1}, {5.3, 2.4},
{8.45, 4.7}, {11.5, 9.6}, {13.8, 7.3}, {12.9, 3.1}, {11, 1.1}}
``````

``````{{13.8, 7.3}, {13.2, 11.9}, {9.5, 14.9}, {6.7, 15.25}, {4.4, 14},
{2.1, 11.1}, {0.6, 5.1}, {5.3, 2.4}, {11, 1.1}, {12.9, 3.1}}
``````

### 样品2

``````{{1, 0}, {1, 1}, {1, -1}, {0.68957, 0.283647}, {0.909487, 0.644276},
{0.0361877, 0.803816}, {0.583004, 0.91555}, {-0.748169, 0.210483},
{-0.553528, -0.967036}, {0.316709, -0.153861}, {-0.79267, 0.585945},
{-0.700164, -0.750994}, {0.452273, -0.604434}, {-0.79134, -0.249902},
{-0.594918, -0.397574}, {-0.547371, -0.434041}, {0.958132, -0.499614},
{0.039941, 0.0990732}, {-0.891471, -0.464943}, {0.513187, -0.457062},
{-0.930053, 0.60341}, {0.656995, 0.854205}}
``````

``````{{1, -1}, {1, 1}, {0.583004, 0.91555}, {0.0361877, 0.803816},
{-0.930053, 0.60341}, {-0.891471, -0.464943}, {-0.700164, -0.750994},
{-0.553528, -0.967036}}
``````

1. 您可以假定输入列表中包含适合您的最小点数。但是，您必须确保正确处理对齐的（子）集。
2. 您可能会在输入列表中找到重复的点
3. 最大点数应仅受可用内存限制
4. 关于“浮点数”：您需要能够处理示例中给出的带有十进制坐标的输入列表。您可以通过使用浮点表示来实现

2

Paul R

@PeterTaylor该示例表明最后一个答案是正确的
John Dvorak

John Dvorak

2

### Ruby，168个字符

``````C=->q{r=[]
f=m=q.sort[0]
t=-0.5
(_,_,t,*f=q.map{|x,y|a=x-f[0]
b=y-f[1]
[0==(d=a*a+b*b)?9:(-t+e=Math.atan2(b,a)/Math::PI)%2,-d,e,x,y]}.sort[0]
r<<=f)while
!r[1]||f!=m
r}``````

``````>p C[[[4.4, 14], [6.7, 15.25], [6.9, 12.8], [2.1, 11.1], [9.5, 14.9],
[13.2, 11.9], [10.3, 12.3], [6.8, 9.5], [3.3, 7.7], [0.6, 5.1], [5.3, 2.4],
[8.45, 4.7], [11.5, 9.6], [13.8, 7.3], [12.9, 3.1], [11, 1.1]]]

[[5.3, 2.4], [11, 1.1], [12.9, 3.1], [13.8, 7.3], [13.2, 11.9], [9.5, 14.9], [6.7, 15.25], [4.4, 14], [2.1, 11.1], [0.6, 5.1]]
``````

2

## Mathematica 151

``````f = For[t = Sort@#; n = 1; l = Pi; a = ArcTan; c@1 = t[[1]],
n < 2 || c@n != c@1,
n++,
(l = a @@ (# - c@n); c[n + 1] = #) & @@
t[[Ordering[Mod[a@## - l, 2 Pi] & @@ (#2 - #1) & @@@ Tuples@{{c@n}, t}, 1]]]] &
``````

``````ClearAll[a, c, t];
s = {{1, 0}, {0.68957, 0.283647}, {0.909487, 0.644276}, {0.0361877, 0.803816},
{0.583004, 0.91555}, {-0.748169, 0.210483}, {-0.553528, -0.967036},
{0.316709, -0.153861}, {-0.79267, 0.585945}, {-0.700164, -0.750994},
{0.452273, -0.604434}, {-0.79134, -0.249902}, {-0.594918, -0.397574},
{-0.547371, -0.434041}, {0.958132, -0.499614}, {0.039941, 0.0990732},
{-0.891471, -0.464943}, {0.513187, -0.457062}, {-0.930053, 0.60341},
{0.656995, 0.854205}};
f@s
Show[Graphics@Line@Table[c@i, {i, n}],
ListPlot[{t, Table[c@i, {i, n}]},
PlotStyle -> {PointSize[Medium], PointSize[Large]},
PlotRange -> All]]
``````

1

# CoffeeScript，276：

``````f=(\$)->z=\$[0];e.r=Math.atan2(e.x-z.x,e.y-z.y)for e in \$;\$.sort((x,y)->(x.r>y.r)-(x.r<y.r));(loop(a=\$[i-1]||\$[\$.length-1];b=\$[i];c=\$[i+1]||\$[0];break if!b;s=(b.x-a.x)*(c.y-b.y)-(b.y-a.y)*(c.x-b.x);break if s<0||!s&&(a.x-b.x)*(b.x-c.x)<0;\$.splice i,1))for i in [\$.length-1..0];\$
``````

``````alert JSON.stringify f({x:e[0], y:e[1]} for e in JSON.parse "
{{1, 1}, {2, 2}, ...}
".replace(/{/g,"[").replace(/}/g,"]"))
``````

belisarius博士博士2013年

@belisarius问题的点与第一个点共线，有时会产生不正确的船体

@belisarius，请将其作为测试用例添加到问题中。
John Dvorak

belisarius博士2013年

1

# Python中，209 205 195

``````from math import*
s=lambda(a,b),(c,d):atan2(d-b,c-a)
def h(l):
r,t,p=[],pi/2,min(l)
while 1:
q=min(set(l)-{p},key=lambda q:(s(p,q)-t)%(2*pi));m=s(p,q);r+=[p]*(m!=t);p=q;t=m
if p in r:return r
``````

belisarius博士2013年

cardboard_box

belisarius博士2013年

belisarius博士2013年