1. 程式人生 > >HDU 4311&4312 Meeting point-1&2 (曼哈頓距離&&切比雪夫距離)

HDU 4311&4312 Meeting point-1&2 (曼哈頓距離&&切比雪夫距離)

題意:平面上有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)倍,

切比雪夫距離便是所得到的新座標系中的曼哈頓距離的二分之一。

然後按照上述題做法直接來即可。

假設有兩點(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)