1455E Four Points(思维+全排列)

1455E Four Points(思维+全排列)

Educational Codeforces Round 99 (Rated for Div. 2)

E. Four Points

题面Four Points

题意:二维平面上有四个点 p 1 , p 2 , p 3 p_1, p_2, p_3 p1,p2,p3 p 4 p_4 p4,现在想让这四个点形成与坐标轴平行的正方形(正方形也可以是一个点),每次操作可以让其中一个点往上下左右移动一个单位距离,问最小的操作次数是多少。

范围 p i = ( x i , y i ) , 0 ≤ x , y ≤ 1 e 9 p_i = (x_i, y_i), 0 \le x, y \le 1e9 pi=(xi,yi),0x,y1e9

分析: 先简化问题,假设这四个点分别对应正方形的 a , b , c , d a, b, c, d a,b,c,d 如下四个顶点,那么如何快速求得答案,即这四个点分别到 a , b , c , d a, b, c, d a,b,c,d 的曼哈顿距离之和。

在这里插入图片描述

首先,不失一般性,我们可以认为点先到达线段所在直线上,再移动到最终的顶点位置,假设我们需要确定线段 a b ab ab,当这条线段位于 p 1 p_1 p1 p 2 p_2 p2 两个点的中间的时候, p 1 p_1 p1 p 2 p_2 p2 到该线段的距离和最小,选择区间为 [ p 1 . x , p 2 . x ] [p_1.x, p_2.x] [p1.x,p2.x]

在这里插入图片描述

对于另一条边 c d cd cd 也是同样的道理, c d cd cd 的选择区间为 [ p 3 . x , p 4 . x ] [p_3.x, p_4.x] [p3.x,p4.x] 中时 p 3 p_3 p3 p 4 p_4 p4 c d cd cd 的距离和最小。

在选定 a b ab ab c d cd cd 之后就可以确定正方形的边长为 l e n ∈ [ l e n 1 , l e n 2 ] len \in [len_1, len_2] len[len1,len2] 如下图所示。

在这里插入图片描述

同理,选定 a c ac ac b d bd bd 两条水平的边也可以确定正方形的边长 l e n ′ ∈ [ l e n 3 , l e n 4 ] len' \in [len_3, len_4] len[len3,len4]

当区间 [ l e n 1 , l e n 2 ] [len_1, len_2] [len1,len2] 与区间 [ l e n 3 , l e n 4 ] [len_3, len_4] [len3,len4] 有交集的时候,说明存在一个边长 l e n len len 同时满足两者的最优解,输出距离和即可。如果没有交集的话,不失一般性,假设 l e n 3 > l e n 2 len_3 > len_2 len3>len2,即区间 [ l e n 3 , l e n 4 ] [len_3, len_4] [len3,len4] 在区间 [ l e n 1 , l e n 2 ] [len_1, len_2] [len1,len2] 的右边如下图。

在这里插入图片描述

显然,这时只有当正方形的边长为 l e n 2 len_2 len2 或者 l e n 3 len_3 len3 时才能得到整体的最优解,但是需要多支出 2 ∗ d i s t 2 * dist 2dist 的代价,因为需要 2 2 2 个点多移动 d i s t dist dist 的距离。

到此,固定了 p 1 , p 2 , p 3 , p 4 p_1, p_2, p_3, p_4 p1,p2,p3,p4 四个点与正方形四个顶点的对应关系下的最优解问题已经解决,但是实际上的对应关系我们还无法确定,因为只有四个点,直接进行 n e x t _ p e r m u t a t i o n next\_permutation next_permutation 全排列枚举取最优解即可。

Code

#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
 
inline int read()
{
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}
 
const int MAXN = 4 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
 
int n, m, k;
 
struct Point
{
	int x, y;
} points[MAXN];

int arr[MAXN];
 
int calc()
{
	Point ld = points[arr[0]], lu = points[arr[1]],
		  rd = points[arr[2]], ru = points[arr[3]];
	int seg_xl = min(abs(max(ld.x, lu.x) - min(rd.x, ru.x)), 
				     abs(min(ld.x, lu.x) - max(rd.x, ru.x)));
	int seg_xr = max(abs(max(ld.x, lu.x) - min(rd.x, ru.x)), 
				     abs(min(ld.x, lu.x) - max(rd.x, ru.x)));
	int seg_yl = min(abs(max(ld.y, rd.y) - min(lu.y, ru.y)), 
					 abs(min(ld.y, rd.y) - max(lu.y, ru.y)));
	int seg_yr = max(abs(max(ld.y, rd.y) - min(lu.y, ru.y)), 
					 abs(min(ld.y, rd.y) - max(lu.y, ru.y)));
	int res = max(ld.x, lu.x) - min(ld.x, lu.x) + 
			  max(rd.x, ru.x) - min(rd.x, ru.x) +
			  max(ld.y, rd.y) - min(ld.y, rd.y) + 
			  max(lu.y, ru.y) - min(lu.y, ru.y) +
			  2 * max(0ll, max(seg_xl, seg_yl) - min(seg_xr, seg_yr));
	return res;
}
 
signed main()
{
    int T = read();
    while (T--)
    {
        for (int i = 0; i < 4; i++)
        {
        	points[i].x = read(), points[i].y = read();
        }
        for (int i = 0; i < 4; i++)
        {
        	arr[i] = i;
        }
        int ans = -1;
        do
        {
        	if (ans < 0) ans = calc();
        	else ans = min(ans, calc());
        } while (next_permutation(arr, arr + 4));
        cout << ans << endl;
    }
    return 0;
}

【END】感谢观看

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值