最大周长

最大周长

给定二维平面上的 $n$ 个不共线的点,这 $n$ 个点组成的多边形是凸多边形 。

这些点按顺时针顺序依次编号为 $1 \sim n$。

我们将两点 $p_1(x_1,y_1)$ 和 $p_2(x_2,y_2)$ 之间的距离定义为它们的曼哈顿距离:$d(p_1,p_2)=|x_1−x_2|+|y_1−y_2|$。

此外,我们将多边形的周长定义为其上所有相邻点对之间的曼哈顿距离之和。

例如,$k$ 个点构成的多边形,其上的点按顺时针顺序依次为 $p_1,p_2, \dots, p_k$,则多边形的周长为 $d(p_1,p_2)+d(p_2,p_3)+ \dots +d(p_k,p_1)$。

对于每个 $k$($3 \leq k \leq n$),请你考虑,从给定的 $n$ 个点中任选 $k$ 个点,构成一个多边形,要求多边形不能是自相交的并且其周长要尽可能长,用 $f(k)$ 来表示周长的最大可能值。

请你计算并输出 $f(3),f(4), \dots ,f(n)$。

注意,多边形不可以自相交,且边必须是直的,例如下图中:

位于中间的多边形无效,因为是自相交多边形;位于右边的多边形无效,因为边不是直的,只有左边的多边形是有效的。

输入格式

第一行包含整数 $n$。

接下来 $n$ 行,每行包含两个整数 $x_i,y_i$,表示其中一个点的横纵坐标。

所有点的坐标两两不同,且点是按照顺时针排列给出的。

输出格式

共一行,对于每个 $i$($3 \leq i \leq n$),输出 $f(i)$。

数据范围

前 $5$ 个测试点满足 $3 \leq n \leq 10$。
所有测试点满足 $3 \leq n \leq 3 \times {10}^{5}$,${−10}^{8} \leq x_i,y_i \leq {10}^{8}$。

输入样例1:

4
2 4
4 3
3 0
1 3

输出样例1:

12 14

输入样例2:

3
0 0
0 2
2 0

输出样例2:

8

 

解题思路 

  一条边的长度是两个节点的曼哈顿距离。一个由$n$个点构成的凸多边形的周长就是相邻两点的曼哈顿距离,其实就是这个凸多边形的外接矩形的周长,如下图:

  (这性质根本想不到...)

  同时还有一个结论,一个凸多边形的任意一个子集(点集,顶点构成的集合)所构成的多边形仍然是凸多边形。(证明见参考资料这里不补充了qwq)

  要想确定这个外接矩形最多需要$4$个点,上边界一个点(所有点中$y$坐标最大的值),下边界一个点(所有点中$y$坐标最小的值),左边界一个点(所有点中$x$坐标最小的值),右边界一个点(所有点中$x$坐标最大的值)。

  因此当$k \geq 4$,求由$k$个点构成的凸多边形时,我们都取这$4$个点,由它构成的矩形的周长一定是最大的(与原来的$n$个点的凸多边形的周长一样),取其他点只会让这个矩形变小。

  当$k=3$,需要特殊处理。可以发现当只能取$3$个点时,构成的矩形的周长一定会比之前的要小。因为三角形只有三个点,而三角形的外接矩形有四条边,因此必定有一个点确定两条边,比如下图位于左下角的点:

  因此可以枚举每一个点,再枚举这个点是外接矩形的左下角、左上角、右上角、右下角这四种情况。当确定这点在哪个拐角处后,另外两个点也确定了,也就是另外两个边界的点(之前四个点中的两个)。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 3e5 + 10, INF = 2e9;
 5 
 6 int x[N], y[N];
 7 
 8 int main() {
 9     int n;
10     scanf("%d", &n);
11     
12     int u = -INF, d = INF, l = INF, r = -INF;
13     for (int i = 0; i < n; i++) {
14         scanf("%d %d", x + i, y + i);
15         u = max(u, y[i]), d = min(d, y[i]); // 确定上下边界
16         l = min(l, x[i]), r = max(r, x[i]); // 确定左右边界
17     }
18     
19     int ret = 0;
20     for (int i = 0; i < n; i++) {   // 3个点的情况
21         ret = max(ret, u - y[i] + r - x[i]);    // 这个点在左下角
22         ret = max(ret, y[i] - d + r - x[i]);    // 这个点在左上角
23         ret = max(ret, y[i] - d + x[i] - l);    // 这个点在右上角
24         ret = max(ret, u - y[i] + x[i] - l);    // 这个点在右下角
25     }
26     printf("%d", ret << 1);
27     
28     for (int i = 4; i <= n; i++) {  // 4个及以上个点的情况,就是n凸多边形的外接矩形的周长
29         printf(" %d", u - d + r - l << 1);
30     }
31     
32     return 0;
33 }

 

参考资料

  AcWing 4605. 最大周长(AcWing杯 - 周赛):https://www.acwing.com/video/4243/

posted @ 2022-08-21 13:20  onlyblues  阅读(208)  评论(0编辑  收藏  举报
Web Analytics