CF685C Optimal Point (数学)

题意

三维空间内给n个点,求一个整点使得到所有点的最大曼哈顿距离最小。
n 1 0 5 n\le10^5

思路

  • 很容易想到二分判定,然后可行域求交。
  • 假如是二维的话旋转一下很好做。
  • 三维的话旋转不好想象,不如直接用更本质的数学方法。
  • 考虑可行域如何表示,二维下只需要四条不等式,三维下需要八条。
  • 做一些换元和奇偶讨论即可。具体可参照题解
  • O ( n log x ) O(n\log x)
#include <bits/stdc++.h>
#define max(a,b) ((a) > (b) ? (a) : (b))
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
const ll inf  =  4e18;
int T, n;
ll x[N], y[N], z[N];
ll ansx, ansy, ansz;

void upp(ll &x) { 
	ll i = 0; for(i = x / 2 - 3; i * 2 < x; i++);
	x = i;
}

void don(ll &x) {
	ll i = 0; for(i = x / 2 + 3; i * 2 > x; i--);
	x = i;
}

bool ok(ll dis) {
	for(int r = 0; r < 2; r++) {
		ll amin = -inf, amax = inf;
		ll bmin = -inf, bmax = inf;
		ll cmin = -inf, cmax = inf;
		ll smin = -inf, smax = inf;
		//2a + r =  x+y-z =  x0+y0-z0-dis ~  x0+y0-z0+dis
		//2b + r =  x-y+z =  x0-y0+z0-dis ~  x0-y0+z0+dis
		//2c + r = -x+y+z = -x0+y0+z0-dis ~ -x0+y0+z0+dis
		//2(a + b + c) + 3r = x+y+z = x0+y0+z0-dis ~ x0+y0+z0+dis
		for(int i = 1; i <= n; i++) {
			amin = max(amin, ( x[i] + y[i] - z[i] - dis - r));
			bmin = max(bmin, ( x[i] - y[i] + z[i] - dis - r));
			cmin = max(cmin, (-x[i] + y[i] + z[i] - dis - r));
			smin = max(smin, ( x[i] + y[i] + z[i] - dis - 3 * r));

			amax = min(amax, ( x[i] + y[i] - z[i] + dis - r));
			bmax = min(bmax, ( x[i] - y[i] + z[i] + dis - r));
			cmax = min(cmax, (-x[i] + y[i] + z[i] + dis - r));
			smax = min(smax, ( x[i] + y[i] + z[i] + dis - 3 * r));
		}
		upp(amin), don(amax);
		upp(bmin), upp(cmin), upp(smin);
		don(bmax), don(cmax), don(smax);
		if (amin > amax || bmin > bmax || cmin > cmax || smin > smax) {
			continue;
		}
		ll sum = amin + bmin + cmin;
		if (sum > smax) continue;
		if (sum - amin + amax >= smin) {
			ll a = amin + max(0, smin - sum);
			ll b = bmin;
			ll c = cmin;
			ansx = a + b + r;
			ansy = a + c + r;
			ansz = b + c + r;
			return 1;
		} else {
			sum += amax - amin;
			if (sum - bmin + bmax >= smin) {
				ll a = amax;
				ll b = bmin + max(0, smin - sum);
				ll c = cmin;
				ansx = a + b + r;
				ansy = a + c + r;
				ansz = b + c + r;
				return 1;
			} else {
				sum += bmax - bmin;
				if (sum - cmin + cmax >= smin) {
					ll a = amax;
					ll b = bmax;
					ll c = cmin + max(0, smin - sum);
					ansx = a + b + r;
					ansy = a + c + r;
					ansz = b + c + r;
					return 1;
				}
			}
		}
	}
	return 0;
}

#define abs(x) ((x) > 0 ? (x) : -(x))
void check() {
	ll mx = 0;
	for(int i = 1; i <= n; i++) {
		mx = max(mx, abs(ansx - x[i]) + abs(ansy - y[i]) + abs(ansz - z[i]));
	}
	cerr << mx << endl;
}

int main() {
	int g = clock();
	freopen("c.in", "r", stdin);
	freopen("c.out","w", stdout);
	for(cin>>T;T;T--) {
		scanf("%d", &n);
		for(int i = 1; i <= n; i++) {
			scanf("%I64d %I64d %I64d", &x[i], &y[i], &z[i]);
		}
		ll l = 0, r = 3e18;
		int cnt = 0;
		while (l <= r) {
			if (ok(l + r >> 1)) {
				r = (l + r >> 1) - 1;
			} else {
				l = (l + r >> 1) + 1;
			}
		}
		check();
		printf("%I64d %I64d %I64d\n", ansx, ansy, ansz);
	}
	cerr << clock() - g << endl;
}

发布了266 篇原创文章 · 获赞 93 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/jokerwyt/article/details/102854626
今日推荐