题意
三维空间内给n个点,求一个整点使得到所有点的最大曼哈顿距离最小。
思路
- 很容易想到二分判定,然后可行域求交。
- 假如是二维的话旋转一下很好做。
- 三维的话旋转不好想象,不如直接用更本质的数学方法。
- 考虑可行域如何表示,二维下只需要四条不等式,三维下需要八条。
- 做一些换元和奇偶讨论即可。具体可参照题解
#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;
}