曼哈顿距离—枚举去绝对值

题目大意:给出 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;
}
 
posted @ 2022-07-13 16:05  JU5T4FUN  阅读(136)  评论(0)    收藏  举报