在平面上有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。描述一个点。# 输出描述:第一行输出最小的距离之和。第二行输出有多少个点,可以达到这个最小距离。
40 00 22 02 2
41
选择(1, 1)
42 11 20 11 0
45
可以选择输入的4个点之一,或者(1, 1)
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
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