P3964 [TJOI2013]松鼠聚会
题目描述
草原上住着一群小松鼠,每个小松鼠都有一个家。时间长了,大家觉得应该聚一聚。但是草原非常大,松鼠们都很头疼应该在谁家聚会才最合理。
每个小松鼠的家可以用一个点 (x,y)(x,y) 表示,两个点的距离定义为点 (x,y)(x,y) 和它周围的 88 个点 (x-1,y)(x−1,y),(x+1,y)(x+1,y),(x,y-1)(x,y−1),(x,y+1)(x,y+1),(x-1,y+1)(x−1,y+1),(x-1,y-1)(x−1,y−1),(x+1,y+1)(x+1,y+1),(x+1,y-1)(x+1,y−1) 距离为 11。
输入格式
第一行是一个整数 NN,表示有多少只松鼠。接下来 NN 行,第 ii 行是两个整数 xx 和 yy,表示松鼠 ii 的家的坐标。
输出格式
一个整数,表示松鼠为了聚会走的路程和最小是多少。
输入输出样例
输入 #1复制
6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2
输出 #1复制
20
输入 #2复制
6
0 0
2 0
-5 -2
2 -2
-1 2
4 0
输出 #2复制
15
说明/提示
样例解释
在第一个样例中,松鼠在第二只松鼠家 (-1,-2)(−1,−2) 聚会;在第二个样例中,松鼠在第一只松鼠家 (0,0)(0,0) 聚会。
数据范围
- 30%30% 的数据,0\le N \le 10000≤N≤1000;
- 100%100%的数据, 0 ≤ N ≤ 1 0 5 0 ≤ N ≤ 105 , − 1 0 9 ≤ x − 1 0 9 ≤ x y ≤ 1 0 9 y ≤ 1 0 9 0\le N \le 10^50≤ N≤105,-10^9 \le x−10^9≤x y \le 10^9 y ≤10^9 0≤N≤1050≤N≤105,−109≤x−109≤xy≤109y≤109。
这题主要是求曼哈顿距离之和,原本题意是求切比雪夫距离的最小值,因为哈曼顿距离计算更加快捷,所以我们转化为哈曼顿的坐标,除二的操作可以在最后结果除。
曼哈顿距离之和推导过程详细
#include<iostream>
#include<algorithm>
#include <climits>
#include <stdio.h>
typedef long long ll;
const ll maxn=1e6 + 5;
using namespace std;
ll x[maxn],y[maxn],hx[maxn],hy[maxn];
ll sumx[maxn],sumy[maxn];
/* 距离最小: 1、输入 1.5、排序,求前缀和 2、切比雪夫转化为哈曼顿坐标系 3、计算到所有点的哈曼顿距离 4、找最小 */
int n;
ll solve(int i){
ll xi=lower_bound(hx+1,hx+1+n,x[i]) -hx;
ll yi=lower_bound(hy+1,hy+n+1,y[i]) -hy;
return xi*1LL*x[i]-sumx[xi]+sumx[n]-sumx[xi]-(n-xi)*1LL*x[i]+
yi*1LL*y[i]-sumy[yi]+sumy[n]-sumy[yi]-(n-yi)*1LL*y[i];
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cin>>n;
int xx,yy;
for(int i=1;i<=n;i++){
cin>>xx>>yy;
x[i]=hx[i]=xx+yy;
y[i]=hy[i]=xx-yy;//转化为哈曼顿坐标系
}
sort(hx+1,hx+n+1);
sort(hy+1,hy+n+1);//如果要使用公式,那么数组必须有序,所以要先排序
for(int i=1;i<=n;i++){
sumx[i]=sumx[i-1]+hx[i];
sumy[i]=sumy[i-1]+hy[i];//提前算好前缀和
}
ll ans=LLONG_MAX;
for(int i=1;i<=n;i++){
ans=min(ans,solve(i));
}
//cout<<(ans>>1LL)<<endl;
printf("%lld", ans >> 1LL);//最后再除二
}
文章评论