题意:平面上有n个点,一个点(x,y)只能到达(x-1,y), (x+1,y), (x, y-1), (x, y+1)4个点。从n个点中找到一点,使其他点到此点的距离之和最小。
思路:
可以发现,两个点间距离为 |x1-x2| + |y1-y2| ,这便是两点间的曼哈顿距离。
朴素的做法是遍历所有点,枚举该点与其他点间的曼哈顿距离之和,但是会TLE;
取巧的做法是将所有点与中心点的曼哈顿距离排序,枚举中间大概250个点左右的情况比较即可(不要欺负人家数据水!
正确姿势:
用结构体数组p[i]保持输入数据x[i],y[i]
将点的x值升序排序求出前i项x和sum1[i],将点的y值升序排序求出前i项y和sum2[i].
求出p[i].x在排序后的x[]中的位置ox,p[i].y在排序后的y[]中的位置oy,则以p[i]为所选中心点的曼哈顿距离之和为
(x_[ox]*(ox-1)-sum1[ox-1]) + (sum1[n]-sum1[ox]-x_[ox]*(n-ox)) + (y_[oy]*(oy-1)-sum2[oy-1]) + (sum2[n]-sum2[oy]-y_[oy]*(n-oy));这个公式的意思就是有ox-1个点的x值小于p[i],n-ox个大于p[i],故可以消去绝对值符号,将曼哈顿距离的前半部分之和求出来。后半部分同理。
code:
/* * @author Novicer * language : C++/C */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> #define INF 2147483647 #define cls(x) memset(x,0,sizeof(x)) #define rise(i,a,b) for(int i = a ; i <= b ; i++) using namespace std; const double eps(1e-8); typedef long long lint; const int maxn = 100000 + 5; int n; lint x_[maxn],y_[maxn]; lint sum1[maxn],sum2[maxn]; struct pt{ int x,y; }; pt p[maxn]; void input(){ cin >> n; for(int i = 1 ; i <= n ; i++){ scanf("%I64d%I64d",&x_[i], &y_[i]); p[i].x = x_[i]; p[i].y = y_[i]; } sort(x_+1,x_+n+1); cls(sum1); for(int i = 1 ; i <= n ; i++) sum1[i] = sum1[i-1] + x_[i]; sort(y_+1,y_+n+1); cls(sum2); for(int i = 1 ; i <= n ; i++) sum2[i] = sum2[i-1] + y_[i]; } void solve(){ lint ans = 1e18; for(int i = 1 ; i <= n ; i++){ lint ox = lower_bound(x_+1 , x_+n+1 , p[i].x) - (x_); lint oy = lower_bound(y_+1 , y_+n+1 , p[i].y) - (y_); lint tmp = 0; tmp += (x_[ox]*(ox-1)-sum1[ox-1]) + (sum1[n]-sum1[ox]-x_[ox]*(n-ox)); tmp += (y_[oy]*(oy-1)-sum2[oy-1]) + (sum2[n]-sum2[oy]-y_[oy]*(n-oy)); ans = min(ans , tmp); } cout << ans << endl; } int main(){ int t;cin >> t; while(t--) { input(); solve(); } return 0; }
题意:平面上有n个点,一个点(x,y)只能到达(x-1,y), (x+1,y), (x, y-1), (x, y+1), (x-1,y+1), (x-1,y-1), (x+1,y+1), (x+1,y-1)8个点。从n个点中找到一点,使其他点到此点的距离之和最小。
思路:可以发现,两个点间距离为 max(|x1-x2|, |y1-y2|),这便是是切比雪夫距离。
我们可以将坐标轴顺时针旋转45度并将所有点的坐标值放大sqrt(2)倍,
切比雪夫距离便是所得到的新坐标系中的曼哈顿距离的二分之一。
然后按照上述题做法直接来即可。
证明如下://证明fromhttp://blog.csdn.net/dgq8211/article/details/7796711
假设有两点(x1,y1), (x2,y2),不妨设 x1>x2。
则Chebyshev距离 D1 = max(|x1-x2|, |y1-y2|)
这两个点对应到新坐标系中的坐标为 (x1-y1, x1+y1), (x2-y2, x2+y2)
某点绕原点逆时针旋转α°(或坐标轴顺时针旋转)后,点(x,y)的坐标会变为(cosα x - sinα y , sinα x + cosα y)。
则Manhattan 距离D2 = |x1-y1-x2+y2| + |x1+y1-x2-y2|
分四种情况讨论:
1.1 y1>y2 && x1-x2>y1-y2
D1 = max(x1-x2, y1-y2) = x1 - x2
D2 = x1-y1-x2+y2 + x1+y1-x2-y2 = 2(x1-x2)
1.2 y1>y2 && x1-x2<=y1-y2
D1 = max(x1-x2,y1-y2) = y1-y2
D2 = -(x1-y1-x2+y2) + x1+y1-x2-y2 = 2(y1-y2)
2.1 y1<=y2 && x1-x2>y2-y1
D1 = max(x1-x2, y2-y1) = x1-x2
D2 = x1-y1-x2+y2 + x1+y1-x2-y2 = 2(x1-x2)
2.2 y1<=y2 && x1-x2<=y2-y1
D1 = max(x1-x2, y2-y1) = y2-y1
D2 = x1-y1-x2+y2 - (x1+y1-x2-y2) = 2(y2-y1)
于是,将Chebyshev距离形式转化成Manhattan距离的形式再求解即可。
code:
/* * @author Novicer * language : C++/C */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> #define INF 2147483647 #define cls(x) memset(x,0,sizeof(x)) #define rise(i,a,b) for(int i = a ; i <= b ; i++) using namespace std; const double eps(1e-8); typedef long long lint; const int maxn = 100000 + 5; int n; int x[maxn],y[maxn]; lint sumx[maxn],sumy[maxn]; lint s1,s2; struct pt{ int x,y; }p[maxn]; void input(){ cin >> n; for(int i = 0 ; i < n ; i++){ scanf("%d%d",&x[i],&y[i]); int tmp = x[i]; x[i] += y[i]; y[i] = tmp - y[i]; p[i].x = x[i];p[i].y = y[i]; } } void solve(){ sort(x,x+n); sort(y,y+n); cls(sumx);cls(sumy); for(int i = 1 ; i <= n ; i++){ sumx[i] = sumx[i-1] + x[i-1]; sumy[i] = sumy[i-1] + y[i-1]; } lint ans = 1e18; for(int i = 0 ; i < n ; i++){ lint px = lower_bound(x , x+n , p[i].x) - x; lint py = lower_bound(y , y+n , p[i].y) - y; lint tmp = 0; lint tmpx = (2*px - n)*p[i].x + sumx[n] - 2*sumx[px]; lint tmpy = (2*py - n)*p[i].y + sumy[n] - 2*sumy[py]; tmp = tmpx + tmpy; ans = min(tmp , ans); } cout << ans / 2 << endl; } int main(){ // freopen("input.txt","r",stdin); int t;cin >> t; while(t--) { input(); solve(); return 0; }
ps.还有一种距离叫做欧拉距离,就是D = sqrt((x1- x2)^2 + (y1 - y2)^2)
版权声明:博主表示授权一切转载:)
HDU 4311&4312 Meeting point-1&2 (曼哈顿距离&&切比雪夫距离)
原文地址:http://blog.csdn.net/qq_15714857/article/details/47175467