多维空间的曼哈顿距离问题
1. 多维空间的任意两点间曼哈顿距离的最大值
2 个点的距离的 4 种算法
(x1-x2) + (y1-y2),
(x1-x2) + (y2-y1),
(x2-x1) + (y1-y2),
(x2-x1) + (y2-y1)
改为:
(x1+y1) - (x2+y2) vs. (-x1-y1) - (-x2-y2)
(x1-y1) - (x2-y2) vs. (-x1+y1) - (-x2+y2)
我们发现上面同一行的两个式子只差一个负号,则对于所有 \(n\) 个点,求出下面 2 个值的最大最小值,相减即可
(x+y),
(x-y)
借助 bitset,我们令 0 表示系数为正,1 表示系数为负,状态 s 和 ~s 只要取一种求最大值最小值即可。
#include <iostream>
#include <bitset>
#include <algorithm>
using namespace std;
const int N = 1e5 + 7, D = 5;
const double INF = 1e18;
double a[N][D];
int n;
bitset<1<<D> st;
int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i)
for (int j = 0; j < D; ++j) scanf("%lf", &a[i][j]);
double ans = 0, mi, mx, sum;
for (int s = 0; s < (1<<D); ++s) {
if (st[s]) continue;
st[s] = st[~s] = 1;
mi = INF, mx = -INF;
for (int i = 0; i < n; ++i) {
sum = 0;
for (int j = 0; j < D; ++j)
if ((1<<j) & s) sum += a[i][j];
else sum -= a[i][j];
mi = min(mi, sum);
mx = max(mx, sum);
}
ans = max(ans, mx - mi);
}
printf("%.2f", ans);
return 0;
}
2. 多维空间中选取若干点的曼哈顿距离之和的最大值
\(k = 1\)
先来考虑 \(k=1\),也即一维的情况。
整个题的贡献可以拆为三个部分:固定点内部互相的贡献、固定点与可选点之间的贡献、可选点内部互相的贡献。
第一种贡献是个定值,可以预处理出来;第二种贡献相当于在选择可选点的时候每个点会有一个额外权值,所以我们主要考虑第三部分,也即可选点内部之间的贡献如何处理。
考虑可选点,由于我们要求的是最大的曼哈顿距离和,且注意到绝对值本身就可以理解成最大值:
也就是说,绝对值此时无关紧要,我们只需要考虑安排好每个数每一维正负号的贡献就好了。
举个例子,假设已经选好了 \(m\) 个点,那么你可以先排序成 \(x_1\le x_2\le \cdots\le x_m\),然后你按贡献计算 \(\sum_{i=1}^m(2i-m-1)x_i=\sum_{i\ne j}|x_i-x_j|\)。我们实际上只需要枚举 \(m!\) 种排列,然后将 \(\sum_{i=1}^m(2i-m-1)x_i\) 的最大值算出来。
所以在一维的情况下,自然可以设一个 DP 出来:设 \(f(i, S)\) 表示前 \(i\) 个点中,已经钦定了一些点位于 \(S\) 这些位置的情况下,所能产生的贡献最大值。此处的 \(S\) 应当是 \(m\) 位二进制数。也就是相当于用状压DP枚举了点坐标大小的 \(m!\) 种排列。
转移时,把第 \(i\) 个点放到第 \(p\) 个位置,贡献将会是 \((2p - m - 1)x _i + c _i\),其中 \(c _i\) 表示第 \(i\) 个点与其他固定点之间的贡献。如此状压 DP,复杂度是 \(O(n m2^m)\),其中 \(n\) 代表可选点数,也即 \(m + t\)。
\(k = 2\)
其实本质上也没有什么区别,只是现在选择第 \(i\) 个点之后要同时考虑 \(x _i\) 和 \(y _i\) 的位置。
设 \(f(i, S_1, S_2)\) 表示前 \(i\) 个点中,已经钦定了一些点的 \(x\) 坐标占据了 \(S_1\) 的位置,\(y\) 坐标占据了 \(S_2\) 的位置,所能产生的贡献最大值。
转移时,把第 \(i\) 个点的 \(x\) 坐标放到 \(p _1\) 的位置,\(y\) 坐标放到 \(p _2\) 的位置,贡献将会是 \((2p _1 - m - 1)x _i + (2p _2 - m - 1)y _i + c _i\),复杂度粗略估计一下大概是 \(O(nm^2 4^m)\),已经可以过了。
但是注意到,\(S _1\) 和 \(S_2\) 互相之间是有限制的,因为他们总需要保证出现的点数相同,不可能会是 \(O(4 ^m)\) 级别的状态量。实际上考虑枚举两个状态中出现的点数 \(k\),状态量应当为
这是 \(O(\frac {4^m} {\sqrt m})\) 的。
拓展:考虑一下有多次询问的情况,以及 \(k=3,4\) 的情况怎么做?

浙公网安备 33010602011771号