HDU--4311(数学)
2015-05-16 01:16:52
题目:给出N个点(1e5),选出一个点,使得这个点到其他所有点的曼哈顿距离和最小。
思路:我们的目标就是统计出每个点到其他点的曼哈顿距离,然后找最小值即可。
先按照每个点的 x 坐标排序,对于第 i 个点,假设我们已经用 sum 保存了前 i-1 个点的 x 坐标和,
那么显然第 i 个点到前面所有点的横向距离和为: (i-1)*xi - sum,(有点容斥的味道)
然后再逆向扫一遍,求出每个点到后面所有点的横向距离和,这样我们就能获得每个点到
其他所有点的横向距离和,同理可以处理出纵向距离(y)。设为:sumx[] 和 sumy[],
最后只要找出 min( sumx[i] + sumy[i] ) 即可。
注意:可先将每个点的坐标 +1e9 以消除负数。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 100010; const ll RA1 = 1e9; const ll RA2 = 1e9 + 1e9; ll sumx[MAXN],sumy[MAXN]; int n; struct point{ int x,y,id; }p[MAXN]; bool cmpx(point a,point b){ return a.x < b.x; } bool cmpy(point a,point b){ return a.y < b.y; } bool cmpid(point a,point b){ return a.id < b.id; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i = 1; i <= n; ++i){ scanf("%d%d",&p[i].x,&p[i].y); p[i].x += RA1; p[i].y += RA1; p[i].id = i; } sort(p + 1,p + n + 1,cmpx); ll sum = 0; for(int i = 1; i <= n; ++i){ int id = p[i].id; sum += p[i].x; sumx[id] = p[i].x * (ll)i - sum; } sum = 0; for(int i = n; i >= 1; --i){ int id = p[i].id; sum += RA2 - p[i].x; sumx[id] += (RA2 - p[i].x) * (ll)(n + 1 - i) - sum; } sort(p + 1,p + n + 1,cmpy); sum = 0; for(int i = 1; i <= n; ++i){ int id = p[i].id; sum += p[i].y; sumy[id] = p[i].y * (ll)i - sum; } sum = 0; for(int i = n; i >= 1; --i){ int id = p[i].id; sum += RA2 - p[i].y; sumy[id] += (RA2 - p[i].y) * (ll)(n + 1 - i) - sum; } sort(p + 1,p + n + 1,cmpid); ll ans = sumx[1] + sumy[1]; for(int i = 2; i <= n; ++i) ans = min(ans,sumx[i] + sumy[i]); printf("%I64d\n",ans); } return 0; }