Title

CF1895B Points and Minimum Distance 题解

题目大意

已知有 2n 个数,第 i 个为 ai,请你把这 2n 个数划分成两组,每组 n 个数,分别作为 n 个点的横纵坐标,已知两个点 (x1,y1)(x2,y2) 之间的距离为 |x1x2|+|y1y2|,请你找到一条路径经过所有的点,并最小化路径的长度。

解题思路

首先,我们对 a 数组从小到大排序,把前 n 个数作为 x、后 n 个数作为 y,然后计算输出即可。

正确性证明

由路径长度的计算方式,易得当一条路径 xy 均具有单调性时,路径长度最短。对于 x 中最小的数 xmin 和最大的数 xmax,显然,不管怎样,必然存在路径上的某一段横向长度为 xmaxxmin,显然此时直接从 xmin 走到 xmax 是最优的,纵向同理。综上,使得所有点的 xy 坐标具有单调性的解法是最优的。那么,接下来需要考虑如何分配 xy。因为此时 xy 需要具有单调性,那么总的路径长度为 xmaxxmin+ymaxymin。设 AB 为可能的 xmaxymin 的值,其中 A<B

xmax=Aymin=B 时,总路径长度 s1=Axmin+ymaxB;当 xmax=Bymin=A 时,总路径长度 s2=Bxmin+ymaxA。此时有 s2s1=BA+BA=2(BA),由 B>A 知,BA>0,所以 s2>s1,因此 s1 为更优解。综上,xmax<ymin 时为最优解,即按照上面所讲的方式分配。

AC 代码

#include<stdio.h>
#include<math.h>
#include<algorithm>
#define N 205
int n,a[N];
int x[N],y[N];
inline void work(){
    scanf("%d",&n);
    for(register int i=1;i<=n<<1;++i)
        scanf("%d",&a[i]);
    std::sort(a+1,a+2*n+1);int ans=0;
    for(register int i=1;i<=n;++i)
        x[i]=a[i],y[i]=a[i+n];
    for(register int i=1;i<n;++i)
        ans+=x[i+1]-x[i]+y[i+1]-y[i];
    printf("%d\n",ans);
    for(register int i=1;i<=n;++i)
        printf("%d %d\n",x[i],y[i]);
}
signed main(){
    int T;scanf("%d",&T);
    while(T--) work();
} 
posted @   UncleSam_Died  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示