HDU4311
题意
给你n个点,再n个点中找一个点,这个点到其他点的曼哈顿距离之和最小
思路
首先说一下曼哈顿距离
∣
x
−
x
i
∣
+
∣
y
−
y
i
∣
\left | x-x_{i} \right |+\left | y-y_{i} \right |
∣x−xi∣+∣y−yi∣
对于这个式子,我们可以先对所有点以
x
x
x坐标从小到大进行排序,并求解前缀和,得到
s
u
m
x
[
]
sumx[]
sumx[]数组,将以
x
x
x排完序的点用一个
i
d
id
id进行记录,然后再对
y
y
y进行排序,同样的对
y
y
y求解前缀和,得到
s
u
m
y
[
]
sumy[]
sumy[]数组,然后我们再枚举一遍点,这个时候因为是对
y
y
y排完序的,当我们枚举到
i
i
i这个点时,
∣
y
−
y
i
∣
\left | y-y_{i} \right |
∣y−yi∣可以利用前缀和数组求出,分成
y
y
y坐标比
i
i
i大的部分和比
i
i
i小的两部分即
s
u
m
y
[
n
]
−
s
u
m
y
[
i
]
−
(
n
−
i
)
∗
a
[
i
]
.
y
+
i
∗
a
[
i
]
.
y
−
s
u
m
y
[
i
]
sumy[n]-sumy[i]-(n-i)*a[i].y+i*a[i].y-sumy[i]
sumy[n]−sumy[i]−(n−i)∗a[i].y+i∗a[i].y−sumy[i]
a
a
a为记录点的结构体数组
s
u
m
y
[
n
]
−
s
u
m
y
[
i
]
−
(
n
−
i
)
∗
a
[
i
]
.
y
sumy[n]-sumy[i]-(n-i)*a[i].y
sumy[n]−sumy[i]−(n−i)∗a[i].y为比
i
i
i大的部分
i
∗
a
[
i
]
.
y
−
s
u
m
y
[
i
]
i*a[i].y-sumy[i]
i∗a[i].y−sumy[i]为比
i
i
i小的部分同样的对于
x
x
x我们之前存了
i
d
id
id所以我们可以利用
i
d
id
id得到同样的式子即
a
[
i
]
.
i
d
∗
a
[
i
]
.
x
−
s
u
m
x
[
a
[
i
]
.
i
d
]
+
s
u
m
x
[
n
]
−
s
u
m
x
[
a
[
i
]
.
i
d
]
−
(
n
−
a
[
i
]
.
i
d
)
∗
a
[
i
]
.
x
a[i].id*a[i].x-sumx[a[i].id]+sumx[n]-sumx[a[i].id]-(n-a[i].id)*a[i].x
a[i].id∗a[i].x−sumx[a[i].id]+sumx[n]−sumx[a[i].id]−(n−a[i].id)∗a[i].x
所以曼哈顿距离之和的最小值可以枚举一遍得出时间复杂度是
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
const int maxn=100005;
struct Point
{
long long x,y,id;
}a[maxn];
long long sumx[maxn],sumy[maxn];
bool cmpx(Point a,Point b)
{
return a.x<b.x;
}
bool cmpy(Point a,Point b)
{
return a.y<b.y;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(sumx,0,sizeof(sumx));
memset(sumy,0,sizeof(sumy));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
}
sort(a+1,a+n+1,cmpx);
sumx[1]=a[1].x;
a[1].id=1;
for(int i=2;i<=n;i++)
{
sumx[i]=sumx[i-1]+a[i].x;
a[i].id=i;
}
sort(a+1,a+n+1,cmpy);
sumy[1]=a[1].y;
for(int i=2;i<=n;i++)
sumy[i]=sumy[i-1]+a[i].y;
long long ans=1LL<<62;
for(int i=1;i<=n;i++)
ans=min(ans,sumy[n]-sumy[i]-(n-i)*a[i].y+i*a[i].y-sumy[i]+a[i].id*a[i].x-sumx[a[i].id]+sumx[n]-sumx[a[i].id]-(n-a[i].id)*a[i].x);
printf("%lld\n",ans);
}
return 0;
}