首都

版权声明:未经过同意不得转载 https://blog.csdn.net/qq_42500298/article/details/82859598

题目描述

在平面上有n个整点(横纵坐标都是整数)牛牛想找到一个整点,使得这个点,到所有点的距离之和最小。两个点的距离定义为从一个点走到另一个点的最小步数。其中每步可以走向相邻8个点(上,下,左,右,左上,左下,右上,右下,类似国际象棋中的王)走一步。输出这个最小的距离之和。 和这个点选择的方案数。(即有多少个点,可以达到这个最小的距离)对于100%的数据,1 <= n <= 100000,|x|, |y| <= 1000000000对于40%的数据,1 <= n <= 100,|x|, |y| <= 100对于以上每部分数据,都有50%的数据n是奇数。注意数据范围是x和y的绝对值,x和y可以是负数。

输入描述:

第一行一个整数n接下来n行,每行两个整数x, y。描述一个点。# 输出描述:第一行输出最小的距离之和。第二行输出有多少个点,可以达到这个最小距离。

示例1

输入

40 00 22 02 2

输出

41

说明

选择(1, 1)

输入

42 11 20 11 0

输出

45

说明

可以选择输入的4个点之一,或者(1, 1)

示例3

输入

30 11 00 0

输出

23

说明

可以选择输入的3个点之一

思路

首先考虑一维的情况非常简单,答案就是中位数,然后如果n是偶数,那么中 间的2个数字之间的数字都可以。对于二维的情况,如果是曼哈顿距离|x1 x2| + |y1 - y2|那么可以两个方向分别考虑。而这个是切比雪夫距离max(|x1 - x2|, |y1 - y2|)可以通过(x , y) -> (x + y, x - y)的方式,转化为曼哈顿距离。 然后这样会有一点小问题,就是如果两个方向上的中位数,奇偶性不同那么 转换回去会出现0.5的情况比如数据40 00 11 01 1最优解是 0.5 0.5 不是整数。 这个时候就检查一下最优解最近的整点(横坐标 ± 0.5, 纵坐标 ± 0.5)然 后另一个情况,就是有多解的情况相当于要求x+y在[L1, R1]区间内,x-y在 [L2, R2]区间内显然x+y和x-y奇偶性需要相同变成了数区间内,奇数的个数 和偶数的个数。

代码

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
long long x[maxn],y[maxn];
int n;
int delta[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
long long calc(long long x0,long long y0)
{
 long long ans=0;
 for(int i=1;i<=n;++i)
  ans+=abs(x[i]-x0)+abs(y[i]-y0);
 return ans>>1;
}
long long calc_even(long long l,long long r)
{
 long long len=(r-l+1);
 if(len&1)
 {
  if((l&1)&&(r&1))
     return len>>1;
  else
   return (len>>1)+1;
 }
 else
 return len>>1;
}
long long calc_odd(long long l,long long r)
{
 long long len=(r-l+1);
 if(len&1)
 {
  if((l&1)&&(r&1))
   return (len>>1)+1;
     else
   return len>>1;
 }
 else
  return len>>1;
}
int main()
{
 scanf("%d",&n);
 long long x0,y0;
  for(int i=1;i<=n;++i)
 {
  scanf("%lld%lld",&x0,&y0);
  x[i]=x0-y0;//变换坐标系
  y[i]=x0+y0;
    //printf("(%d%d)\n",x[i],y[i]);
 }
 sort(x+1,x+1+n);
 sort(y+1,y+1+n);
 if(n&1)
 {
  long long mid_x=x[n+1>>1];
    long long mid_y=y[n+1>>1];
  if(!((mid_x+mid_y)&1))//该点是格点
  {
   printf("%lld\n1\n",calc(mid_x,mid_y));
  }
  else
    {
   long long mm=LLONG_MAX;
   int cnt=1;
   for(int i=0;i<4;++i)//感觉可能就是四种
   {
       long long t=calc(mid_x+delta[i][0],mid_y+delta[i][1]);
    if(t<mm)
     mm=t,cnt=1;
    else
     if(t==mm)
      ++cnt;
         }
   printf("%lld\n%d\n",mm,cnt);
  }
 }
 else
 {
  long long x_l=x[n/2],x_r=x[n/2+1];
  long long y_l=y[n/2],y_r=y[n/2+1];
    if(x_l==x_r&&y_l==y_r)
  {
   if((x_l+y_l)&1)
   {
    long long mm=LLONG_MAX;
    int cnt=1;
        for(int i=0;i<4;++i)
    {
     long long t=calc(x_l+delta[i][0],y_l+delta[i][1]);
     if(t<mm)
      mm=t,cnt=1;
           else
      if(t==mm)
       ++cnt;
    }
    printf("%lld\n%d\n",mm,cnt);
       }
   else
   {
    printf("%lld\n1\n",calc(x_l,y_l));
   }
  }
  else
    {
   printf("%lld\n",calc(x_l,y_l));
   //计算a*b的矩形内的格点个数
   long long evenx=calc_even(x_l,x_r),oddx=calc_odd(x_l,x_r),
   eveny=calc_even(y_l,y_r),oddy=calc_odd(y_l,y_r);
   printf("%lld\n",evenx*eveny+oddx*oddy);
  }
 }
 return 0;
}

来源:nkw

猜你喜欢

转载自blog.csdn.net/qq_42500298/article/details/82859598