1. 程式人生 > 其它 >切比雪夫距離

切比雪夫距離

曼哈頓距離

若點 \(A(x_1,y_1),B(x_2,y_2)\) 則兩點間的曼哈頓距離為 \(|x_1-x_2|+|y_1-y_2|\)

已知 \(n\) 個點求兩兩之間的曼哈頓距離之和,易得 \(x\) 的貢獻與 \(y\) 的貢獻是分開的

可以用兩次排序去絕對值 + 字首和解決

複雜度 \(O(n\log n)\)

切比雪夫距離

曼哈頓距離是 4 向移動的最少步數,切比雪夫距離則是 8 向移動最少步數

即對於 \(A(x_1,y_1),B(x_2,y_2)\) 兩點的切比雪夫距離為 \(\max(|x_1-x_2|,|y_1-y_2|)\)

問題:給定 \(n\) 個點,求兩兩之間的切比雪夫距離之和

此時 \(x,y\) 的貢獻不能單獨算了,怎麼辦?

轉換

將原座標系逆時針旋轉 \(45^{\circ}\) ,再放大 \(\sqrt{2}\)

會發現:此(座標系中的曼哈頓距離)是(原座標系中切比雪夫距離)的 2 倍

考慮 \((x_1,y_1)\) 旋轉後的座標 \((x_2,y_2)\)

\(x_2=x_1\cos 45^{\circ}-y_1\sin 45^{\circ}=\dfrac{1}{\sqrt{2}}(x_1-y_1)\)

\(y_2=y_1\cos 45^{\circ}+x_1\sin 45^{\circ}=\dfrac{1}{\sqrt{2}}(x_1+y_1)\)

放大了 \(\sqrt{2}\) 倍,所以 \(x_2=x_1-y_1,y_2=x_1+y_1\)

轉換成曼哈頓距離,同樣 \(O(n\log n)\) 求,最後除以 2

給一個 \(n\times m\) 的棋盤,兩個玩家有 'S''M' 兩種國王,國王八向移動

傳播值定義為玩家國王兩兩之間距離和,要分別求兩個玩家的傳播值

板子(確信)

code

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
typedef long double LD;
typedef long long LL;
typedef double db;
const int N = 1005;
int n, m, tot;
struct poi { int x, y; } a[N * N];
LL tt, sm;
char mp[N][N];
inline bool cmp1(poi A, poi B) { return A.x < B.x; }
inline bool cmp2(poi A, poi B) { return A.y < B.y; }
inline void sol(char Ch) {
    tot = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (mp[i][j] == Ch) a[++tot] = (poi){ i - j, i + j };
    sort(a + 1, a + tot + 1, cmp1);
    sm = tt = 0;
    for (int i = 1; i <= tot; i++) sm += a[i].x * (i - 1) - tt, tt += a[i].x;
    sort(a + 1, a + tot + 1, cmp2), tt = 0;
    for (int i = 1; i <= tot; i++) sm += a[i].y * (i - 1) - tt, tt += a[i].y;
    printf("%lld ", sm / 2);
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
    sol('M'), sol('S');
}