曼哈顿距离—枚举去绝对值
题目大意:给出 d 维空间的 n 个点,求曼哈顿距离最大的两个点的曼哈顿距离
暴力:$O(n^2)$,需要考虑优化
首先考虑二维
对于两个点$(x_1,y_1) , (x_2,y_2)$,它们的曼哈顿距离为$d=|x_1-x_2|+|y_1-y_2|$
去掉绝对值,有四种情况,整理得
$d_1=x_1-x_2+y_1-y_2=(x_1+y_1)-(x_2+y_2) $
$d_2=x_1-x_2+y_2-y_1=(x_1-y_1)-(x_2-y_2) $
$d_3=x_2-x_1+y_1-y_2=(-x_1+y_1)-(-x_2+y_2) $
$d_4=x_2-x_1+y_2-y_1=(-x_1-y_1)-(-x_2-y_2) $
d是$d_{1...4}$中最大的一个
我们记录每个点p[i]的4种状态
存入数组d[i] [4]中,对d数组排序
遍历求出mx-mi作为这个状态下的最大答案,之后在$d_{1...4}$贡献的答案中取最大值就是最终答案
不难向高维拓展,状态数为$2^n$个(每个维度坐标取遍0,1)
采用状态压缩,用[0,2^n-1]的数来表示
方便起见,下标改成从0开始
主要思想:
原本要两个点才能求解的问题,转化为一个点本身的某种性质能贡献多少答案,这样只用计算一对元素(原本所有元素两两配对)。
n个绝对值相加,可以拆成多个$2^n$个式子的最大值,枚举即可
例题:洛谷 P1648看守
#include<bits/stdc++.h> #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define endl '\n' #define lowbit(a) a&(-a) typedef long long ll; using namespace std; //#define int long long const int N = 2e6 + 5; int n, dim; int p[10]; int d[18][N]; // 2^4=16 signed main() { ios; cin >> n >> dim; for (int i = 1; i <= n; ++i) { for (int j = 0; j < dim; ++j) { cin >> p[j]; } for (int j = 0; j < (1 << dim); ++j) { //0-2^n -1个状态 for (int k = 0; k < dim; ++k) { //遍历二进制的每一位 if (j & (1 << k)) d[j][i] += p[k]; else d[j][i] -= p[k]; } } } int ans = -1, res, mi, mx; for (int i = 0; i < (1 << dim); ++i) { mi = 0x3f3f3f3f, mx = -0x3f3f3f3f; //小细节,之前mx习惯性赋值成-1了,实际上可能元素全是负数,-1比最大值还大 for (int j = 1; j <= n; ++j) { mi = min(mi, d[i][j]), mx = max(mx, d[i][j]); } res = mx - mi; ans = max(ans, res); } cout << ans << endl; return 0; }

浙公网安备 33010602011771号