📅  最后修改于: 2023-12-03 15:12:46.931000             🧑  作者: Mango
这是一道来自门|门 IT 2008年的编程题,旨在考察程序员对算法的掌握和实现能力。
有一张无边无界的白纸,上面有 $n$ 个点。现按极角排序将这些点标号为 $1,2,\ldots, n$。现从第 $1$ 点开始逆时针依次连接所有的点,形成一个凸包。求凸包周长的整数部分。
凸包算法的经典思路是 Graham 扫描法。它的基本步骤如下:
以下是一个使用 Python 实现 Graham 扫描法求凸包周长的示例程序:
def cross(x1, y1, x2, y2, x3, y3):
return (x2 - x1) * (y3 - y2) - (x3 - x2) * (y2 - y1)
def graham_scan(n, x, y):
p = [(x[i], y[i]) for i in range(n)]
p.sort()
stk = []
for i in range(n):
while len(stk) >= 2 and cross(stk[-2][0], stk[-2][1], stk[-1][0], stk[-1][1], p[i][0], p[i][1]) < 0:
stk.pop()
stk.append((p[i][0], p[i][1]))
for i in range(n - 1, -1, -1):
while len(stk) >= 2 and cross(stk[-2][0], stk[-2][1], stk[-1][0], stk[-1][1], p[i][0], p[i][1]) < 0:
stk.pop()
stk.append((p[i][0], p[i][1]))
ans = 0
for i in range(len(stk) - 1):
ans += (stk[i + 1][0] - stk[i][0]) ** 2 + (stk[i + 1][1] - stk[i][1]) ** 2
return int(ans ** 0.5 + 0.5)
n = int(input())
x = []
y = []
for i in range(n):
xi, yi = map(int, input().split())
x.append(xi)
y.append(yi)
print(graham_scan(n, x, y))
代码中 cross()
函数计算 $3$ 个点构成的向量叉积,graham_scan()
函数实现了 Graham 扫描法的流程,最后将答案四舍五入输出。注意,这里的求凸包周长用到了勾股定理,但由于 Python 中整数空间大小无限,所以没有必要使用 sqrt()
函数求根,直接将答案取平方再四舍五入即可。