Khoảng cách Manhattan và phép xoay 45 độ
Khoảng cách Manhattan giữa hai điểm là : số bước ngắn nhất để đi giữa hai ô trên lưới khi chỉ được đi lên, xuống, trái, phải. Trang này gom các kỹ thuật chuyên cho khoảng cách này. Kỹ thuật trung tâm là phép xoay 45 độ , , biến Manhattan thành khoảng cách Chebyshev . Nhờ phép xoay, "hình thoi" trở thành hình vuông song song trục, và các bài như tính tổng trong hình thoi cho mọi tâm hay tìm cặp điểm xa nhất đều giải được trong mỗi truy vấn hoặc cho cả tập, thay vì mỗi tâm hay mọi cặp. Đây là một chủ đề con của hình học tính toán, nhưng gần như chỉ dùng số nguyên và không cần tích có hướng.
Ý tưởng / Trực giác
Ba cách đo khoảng cách trên lưới
Với độ lệch , :
| Tên | Công thức | Ý nghĩa trên lưới | "Hình tròn" bán kính |
|---|---|---|---|
| Manhattan () | số bước đi 4 hướng (xe, người đi bộ trong khu phố ô cờ) | hình thoi | |
| Chebyshev () | số nước đi của quân vua (8 hướng) | hình vuông song song trục | |
| Euclid () | đường chim bay | hình tròn |
"Hình tròn" ở cột cuối là tập các điểm cách tâm không quá . Chính hình dạng của nó quyết định bài có dễ hay không: hình vuông song song trục là thứ ta xử lý giỏi nhất (tổng tiền tố 2D, quét, cây phân đoạn), còn hình thoi thì không.
Phép xoay 45 độ: Manhattan thành Chebyshev
Đặt , . Khi đó với mọi hai điểm:
Chứng minh. Với hai số thực bất kỳ, là giá trị lớn nhất của khi (chọn cùng dấu với , cùng dấu với ). Bốn tổ hợp dấu cho bốn giá trị , , , , nên
Thay , là xong.
Chiều ngược lại cũng đúng: , nên bài Chebyshev (quân vua) cũng xoay được về Manhattan. Phép biến đổi ngược là , .
Về hình học, là phép xoay kèm phóng to lần (và một phép lật, không ảnh hưởng gì). Bốn cạnh của hình thoi nằm trên các đường và , tức và : sau khi đổi biến, chúng thành các cạnh song song trục.
Hình thoi thành hình vuông
Hình thoi tâm bán kính là . Theo công thức trên, đó chính là
một hình vuông cạnh song song trục trong mặt phẳng . Mọi công cụ cho hình chữ nhật dùng được ngay:
- Tổng trong hình thoi: dựng tổng tiền tố 2D trên lưới đã xoay, mỗi hình thoi là một truy vấn hình chữ nhật .
- Cặp điểm xa nhất: khoảng cách Chebyshev lớn nhất là , vì hai trục tách rời nhau trong phép lấy .
- Đặt hình thoi phủ nhiều điểm nhất: thành đặt hình vuông, giải bằng sweep line và cây phân đoạn.
Tách trục: khi không cần xoay
Với tổng khoảng cách, không cần xoay: , mỗi trục là một bài một chiều độc lập. Hai bài một chiều kinh điển:
- Tổng trên mọi cặp: sau khi sắp xếp, đứng sau đúng phần tử không lớn hơn nó (chỉ số từ ), nên nó đóng góp . Một lần sắp xếp và một biến tiền tố là đủ, .
- Điểm làm nhỏ nhất là trung vị. Khi dịch sang phải một đơn vị, mọi điểm ở bên trái hoặc tại xa thêm , mọi điểm ở bên phải hẳn gần lại . Chừng nào số điểm ở bên phải hẳn còn nhiều hơn số điểm ở bên trái hoặc tại thì dịch tiếp còn có lợi; dừng lại đúng khi hai bên cân bằng, tức ở trung vị. Với chẵn, mọi nằm giữa hai phần tử giữa đều tối ưu như nhau.
Trong 2D, điểm gặp tối ưu (tổng khoảng cách Manhattan tới điểm nhỏ nhất) là , vì hai trục độc lập. Lưu ý điểm này không nhất thiết là một trong điểm đã cho.
Ngược lại, max và min khoảng cách thì không tách trục được (, vì hai giá trị lớn nhất có thể đến từ hai cặp khác nhau). Đó là lúc cần phép xoay.
Ví dụ chạy tay
Xoay lưới và tính tổng trong hình thoi
Lưới (hàng , cột , đánh số từ ). Để chỉ số không âm, dùng , , cả hai nằm trong , nên lưới xoay có kích thước với .
Lưới gốc (giá trị) (u, v) của từng ô
j=0 j=1 j=2 j=0 j=1 j=2
i=0 3 1 4 i=0 (0,2) (1,1) (2,0)
i=1 1 5 9 i=1 (1,3) (2,2) (3,1)
i=2 2 6 5 i=2 (2,4) (3,3) (4,2)
Lưới xoay S x S (dấu . là ô không ứng với ô nào, giá trị 0)
v=0 v=1 v=2 v=3 v=4
u=0 . . 3 . .
u=1 . 1 . 1 .
u=2 4 . 5 . 2
u=3 . 9 . 6 .
u=4 . . 5 . .
Lưới gốc "đứng trên một đỉnh" sau khi xoay; các ô thật chỉ nằm ở những vị trí có chẵn, các vị trí còn lại bằng .
Truy vấn 1: hình thoi tâm (ô giá trị ), bán kính . Tâm có , . Hình vuông , :
v=0 v=1 v=2 v=3 v=4
u=0 . . 3 . .
u=1 . [ 1 . 1 ] .
u=2 4 [ . 5 . ] 2 tổng = 1 + 1 + 5 + 9 + 6 = 22
u=3 . [ 9 . 6 ] .
u=4 . . 5 . .
Đúng bằng tổng năm ô của hình thoi. Hai ô và ở hàng bị loại vì chúng cách tâm .
Truy vấn 2: tâm (ô góc, giá trị ), bán kính . Tâm có , , hình vuông là , . Phần nằm ngoài lưới xoay bị kẹp về , : tổng ba hàng đầu , đúng bằng tổng các ô có .
Bốn điểm: cặp xa nhất, tổng khoảng cách, điểm gặp
Cho , , , .
y
5 . . C . . . .
4 . . . . . . D
3 . . . . . . .
2 . . . . B . .
1 . A . . . . .
0 1 2 3 4 5 6 x
| Điểm | ||||
|---|---|---|---|---|
| A | 1 | 1 | 2 | 0 |
| B | 4 | 2 | 6 | 2 |
| C | 2 | 5 | 7 | -3 |
| D | 6 | 4 | 10 | 2 |
- Cặp xa nhất: (cặp ), (cặp hoặc ). Đáp án . Kiểm tra: .
Tổng khoảng cách mọi cặp: trục đã sắp là :
tiền tố trước đóng góp 0 1 0 0 1 2 1 1 2 4 3 5 3 6 7 11 Tổng trục là . Làm tương tự với trục () được . Đáp án . Kiểm tra bằng sáu cặp: .
- Điểm gặp tối ưu: trung vị là bất kỳ giá trị nào trong , trung vị trong . Chọn : tổng khoảng cách , và không điểm nguyên nào cho tổng nhỏ hơn.
Cài đặt
C++: tổng lớn nhất trong hình thoi bán kính (lưới xoay + tổng tiền tố 2D)
Đọc lưới và , in tổng lớn nhất của một hình thoi bán kính có tâm là một ô bất kỳ (hình thoi được phép tràn ra ngoài lưới, phần tràn không có giá trị). Giá trị trong lưới có thể âm.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, S; // grid n x m, rotated grid S x S, S = n + m - 1
vector<vector<ll>> P; // P[u+1][v+1]: prefix sums on the rotated grid
// Sum over rotated cells with u in [u1, u2], v in [v1, v2], clamped to the grid.
ll rectSum(int u1, int v1, int u2, int v2) {
u1 = max(u1, 0); v1 = max(v1, 0);
u2 = min(u2, S - 1); v2 = min(v2, S - 1);
if (u1 > u2 || v1 > v2) return 0;
return P[u2 + 1][v2 + 1] - P[u1][v2 + 1] - P[u2 + 1][v1] + P[u1][v1];
}
// Sum of all cells (i, j) with |i - r| + |j - c| <= k.
ll diamondSum(int r, int c, int k) {
int u = r + c, v = r - c + (m - 1);
return rectSum(u - k, v - k, u + k, v + k);
}
int main() {
int k;
scanf("%d %d %d", &n, &m, &k);
S = n + m - 1;
P.assign(S + 1, vector<ll>(S + 1, 0));
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
ll g; scanf("%lld", &g);
P[i + j + 1][i - j + (m - 1) + 1] = g; // (u, v) = (i + j, i - j + m - 1)
}
for (int u = 1; u <= S; u++) // standard 2D prefix sums
for (int v = 1; v <= S; v++)
P[u][v] += P[u - 1][v] + P[u][v - 1] - P[u - 1][v - 1];
ll best = LLONG_MIN; // values may be negative
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
best = max(best, diamondSum(i, j, k));
printf("%lld\n", best);
}
Nếu mỗi tâm có bán kính riêng (ví dụ bán kính lớn nhất thỏa một điều kiện), chỉ cần gọi diamondSum(i, j, r[i][j]); phần dựng lưới xoay giữ nguyên.
C++: các công thức trên tập điểm
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// Max Manhattan distance over all pairs: max(max u - min u, max v - min v).
ll maxPairDist(const vector<ll>& x, const vector<ll>& y) {
ll uMax = LLONG_MIN, uMin = LLONG_MAX, vMax = LLONG_MIN, vMin = LLONG_MAX;
for (size_t i = 0; i < x.size(); i++) {
ll u = x[i] + y[i], v = x[i] - y[i];
uMax = max(uMax, u); uMin = min(uMin, u);
vMax = max(vMax, v); vMin = min(vMin, v);
}
return max(uMax - uMin, vMax - vMin);
}
// Sum of |a_i - a_j| over all pairs i < j (one axis).
ll sumPairs1D(vector<ll> a) {
sort(a.begin(), a.end());
ll prefix = 0, total = 0;
for (size_t i = 0; i < a.size(); i++) {
total += a[i] * (ll)i - prefix; // a[i] minus each of the i smaller values
prefix += a[i];
}
return total;
}
ll sumPairDist(const vector<ll>& x, const vector<ll>& y) {
return sumPairs1D(x) + sumPairs1D(y); // axes are independent
}
// Point minimising total Manhattan distance: (median x, median y).
pair<ll, ll> bestMeetingPoint(vector<ll> x, vector<ll> y) {
size_t mid = (x.size() - 1) / 2;
nth_element(x.begin(), x.begin() + mid, x.end());
nth_element(y.begin(), y.begin() + mid, y.end());
return {x[mid], y[mid]};
}
// d dimensions: fix the sign of coordinate 0, try all 2^(d-1) sign patterns.
ll maxPairDistD(const vector<vector<ll>>& p) {
int d = p[0].size();
ll best = 0;
for (int mask = 0; mask < (1 << (d - 1)); mask++) {
ll hi = LLONG_MIN, lo = LLONG_MAX;
for (auto& q : p) {
ll s = q[0];
for (int k = 1; k < d; k++) s += (mask >> (k - 1) & 1) ? -q[k] : q[k];
hi = max(hi, s); lo = min(lo, s);
}
best = max(best, hi - lo);
}
return best;
}
int main() {
int n;
scanf("%d", &n);
vector<ll> x(n), y(n);
for (int i = 0; i < n; i++) scanf("%lld %lld", &x[i], &y[i]);
auto [mx, my] = bestMeetingPoint(x, y);
printf("%lld %lld %lld %lld\n", maxPairDist(x, y), sumPairDist(x, y), mx, my);
}
Với bốn điểm ở ví dụ trên, chương trình in 8 31 2 2.
Python
import sys
def max_pair_dist(pts):
# rotate: Manhattan becomes Chebyshev
us = [x + y for x, y in pts]
vs = [x - y for x, y in pts]
return max(max(us) - min(us), max(vs) - min(vs))
def sum_pairs_1d(a):
a = sorted(a)
total = prefix = 0
for i, val in enumerate(a):
total += val * i - prefix
prefix += val
return total
def sum_pair_dist(pts):
return sum_pairs_1d([x for x, _ in pts]) + sum_pairs_1d([y for _, y in pts])
def main():
data = sys.stdin.buffer.read().split()
n = int(data[0])
pts = [(int(data[1 + 2 * i]), int(data[2 + 2 * i])) for i in range(n)]
print(max_pair_dist(pts), sum_pair_dist(pts))
main()
Python không lo tràn số, nhưng với cỡ nên đọc nhanh bằng sys.stdin.buffer như trên.
Độ phức tạp
| Bài toán | Thời gian | Bộ nhớ | Lý do |
|---|---|---|---|
| Tổng trong hình thoi, lưới | dựng , mỗi truy vấn | lưới xoay có ô; mỗi truy vấn là bốn phép cộng trừ | |
| Cặp điểm xa nhất (2D) | ngoài input | một lượt tìm min, max của và | |
| Cặp điểm xa nhất ( chiều) | mỗi bộ dấu một lượt min, max | ||
| Tổng khoảng cách mọi cặp | chi phí nằm ở sắp xếp; phần cộng dồn là | ||
| Điểm gặp tối ưu | trung bình | nth_element tìm trung vị không cần sắp xếp đủ |
|
| MST Manhattan | chỉ cạnh ứng viên (xem phần mở rộng) |
Duyệt trâu tương ứng: tổng hình thoi bán kính tốn mỗi tâm, tức cho mọi tâm; cặp xa nhất và tổng mọi cặp tốn .
⚠️ Lỗi thường gặp
- Chỉ số âm trên lưới xoay. có thể âm (nhỏ nhất là ). Phải cộng thêm một độ dời bất kỳ (gọn nhất là đúng ), kèm tăng kích thước lưới xoay tương ứng nếu chọn độ dời lớn hơn, và dùng cùng độ dời ở cả lúc dựng lẫn lúc truy vấn. Lưu ý có thể nhỏ hơn , nên cộng không phải lúc nào cũng đủ. Triệu chứng: truy cập ra ngoài mảng hoặc kết quả lệch chỉ ở các ô gần cạnh trái.
- Lưới xoay có kích thước sai. chạy tới nên lưới xoay có cạnh , không phải hay . Với lưới vuông thì cạnh là , bộ nhớ gấp khoảng bốn lần lưới gốc; cho khoảng số
long long, vẫn ổn, nhưng hãy tính trước. - Lưới dẹt làm nổ bộ nhớ. Với , , lưới gốc chỉ có ô nhưng lưới xoay có ô. Khi và chênh lệch lớn, thay bằng tổng tiền tố theo từng hàng: hình thoi giao mỗi hàng thành một đoạn, truy vấn .
- Quên kẹp hình vuông vào lưới. Hình thoi ở gần biên có hoặc . Không kẹp thì đọc ra ngoài mảng tiền tố. Nếu đề yêu cầu hình thoi nằm trọn trong lưới (như bài trại bò tót), phải giới hạn bán kính bởi khoảng cách tới biên, việc kẹp không thay cho điều kiện này.
- Khởi tạo đáp án max bằng . Nếu lưới có giá trị âm, mọi tổng hình thoi có thể âm và
best = 0in ra sai. Ví dụ lưới gồm với : đáp án đúng là . Khởi tạo bằngLLONG_MIN(như chương trình trên) hoặc bằng tổng của tâm đầu tiên; chỉ khi đề bảo đảm giá trị không âm thì mới được dùng . - Tính chẵn lẻ khi đổi ngược. Chỉ những có mới ứng với điểm nguyên . Nếu tìm được tâm tối ưu trong mặt phẳng mà lẻ, tâm thật có tọa độ nửa nguyên. Bài cho đặt tâm ở vị trí thực thì chấp nhận được; bài bắt tâm là ô lưới thì phải chỉ duyệt các đúng chẵn lẻ.
- Tràn số. Tọa độ tới thì tới , vượt
int. Tổng khoảng cách mọi cặp với có thể tới cỡ , sát giới hạnlong long; đề thường cho lấy modulo hoặc ràng buộc nhỏ hơn, hãy đọc kỹ. - Tách trục cho bài max. không bằng . Với , , : cách sai cho , nhưng ba cặp có khoảng cách , , nên đáp án đúng là (cặp có lớn nhất và cặp có lớn nhất là hai cặp khác nhau). Chỉ tổng mới tách trục được; max và min phải xoay.
- Nhầm trung bình với trung vị. Điểm làm tổng bình phương khoảng cách nhỏ nhất là trung bình cộng; với tổng khoảng cách Manhattan thì là trung vị. Dùng trung bình cho bài sai ngay cả trên ba điểm .
- Dùng BFS khi không có vật cản. Trên lưới không vật cản, BFS 4 hướng từ một ô chỉ tính lại công thức với chi phí . BFS đa nguồn thì khác: nó cho khoảng cách Manhattan tới tập nguồn gần nhất, thứ mà công thức đơn lẻ không cho. Ngược lại, có vật cản thì khoảng cách thật luôn và có thể lớn hơn hẳn, nên mọi công thức trên trang này không còn dùng được.
Biến thể / Mở rộng
Không gian chiều: bộ dấu
Tổng quát của chứng minh ở trên: . Vậy
Bộ dấu và cho cùng hiệu , nên chỉ cần cố định và thử bộ còn lại (hàm maxPairDistD ở trên). Với đó chính là hai trục và . Khi hoặc , cách này nhanh hơn nhiều so với .
Điểm xa nhất tính từ một điểm truy vấn
Với điểm truy vấn có , khoảng cách Manhattan lớn nhất tới tập điểm là
Chỉ cần lưu bốn giá trị cực trị, mỗi truy vấn . Nếu tập điểm có thêm, xóa thì lưu và trong hai multiset.
Khoảng cách Chebyshev và bài quân vua
Số nước đi ít nhất của quân vua là : đi chéo bước, rồi đi thẳng phần còn lại. Tổng khoảng cách Chebyshev mọi cặp tính được bằng cách xoay ngược: , rồi tách trục , như bài tổng Manhattan.
BFS trên lưới 4 hướng
Trên lưới không có vật cản, BFS 4 hướng từ ô cho đúng , BFS 8 hướng cho khoảng cách Chebyshev. BFS đa nguồn từ tập cho mỗi ô giá trị trong , hữu ích khi cần "bán kính lớn nhất trước khi hình thoi chạm vào một ô xấu". Kết hợp với lưới xoay: BFS cho bán kính, tổng tiền tố trên lưới xoay cho tổng trong hình thoi.
Hình thoi tâm tùy ý: đặt hình vuông phủ nhiều điểm nhất
Khi tâm được đặt ở vị trí thực bất kỳ, bài "hình thoi bán kính chứa tổng trọng số lớn nhất" thành "hình vuông cạnh song song trục chứa tổng lớn nhất" trong mặt phẳng . Đó là bài sweep line kinh điển: mỗi điểm tạo ra khoảng vị trí góc hình vuông mà nó được phủ, quét theo với cửa sổ độ rộng , dùng cây phân đoạn cộng đoạn, lấy max theo (tọa độ cần nén).
Cây khung nhỏ nhất Manhattan (MST Manhattan)
Đồ thị đầy đủ trên điểm với trọng số Manhattan có cạnh, quá nhiều khi . Tính chất then chốt: chia mặt phẳng quanh điểm thành 8 góc (tám góc phần tám). Nếu và cùng nằm trong một góc của và gần hơn thì , nên cạnh là cạnh nặng nhất trên chu trình và có thể bỏ. Vậy mỗi điểm chỉ cần nối với điểm gần nhất trong mỗi góc, tổng cộng không quá cạnh ứng viên (do đối xứng, xét góc là đủ, còn cạnh).
Điểm gần nhất trong một góc tìm được cho mọi điểm bằng một lượt quét: sắp theo một tọa độ, duy trì cây Fenwick trên (đã nén) lưu điểm có nhỏ nhất. Lặp lại với phép biến đổi tọa độ (đổi chỗ và đổi dấu ), rồi chạy Kruskal trên cạnh. Tổng . Phần Kruskal và các tính chất cây khung xem ở cây khung nhỏ nhất.
Cặp điểm gần nhất theo Manhattan
Bài cặp điểm gần nhất với khoảng cách Manhattan chạy trực tiếp được bằng khung chia để trị chuẩn, không cần xoay: với là đáp án tốt nhất hiện tại, trong dải chỉ giữ các điểm có so với đường chia, rồi mỗi điểm chỉ so với các điểm có (hình vuông này bao trọn hình thoi bán kính , nên không bỏ sót cặp nào). Nếu muốn, có thể xoay sang Chebyshev để lọc chính xác: sau khi xoay, "hình tròn" láng giềng đã là hình vuông song song trục, nên phép lọc theo từng trục không còn giữ lại điểm thừa ở các góc.
"Nằm giữa" theo Manhattan
khi và chỉ khi nằm trong hình chữ nhật bao của và (tức nằm giữa và nằm giữa ), vì đẳng thức phải xảy ra trên từng trục. Khác với Euclid (chỉ đúng khi nằm trên đoạn thẳng ), tập các điểm "nằm giữa" theo Manhattan là cả một hình chữ nhật, và giữa hai điểm có rất nhiều đường đi ngắn nhất. Tính chất này hay dùng để đếm đường đi ngắn nhất trên lưới hoặc để nhận ra cấu trúc đơn điệu ẩn trong đề.
Bài tập luyện
Luyện kỹ thuật
- Đường đi ngắn nhất của vua (kingpath) (Nghiệp dư) số nước đi ít nhất của quân vua là khoảng cách Chebyshev ; in đường đi bằng cách đi chéo trước rồi đi thẳng.
- Bò Lười (Silver) (lazycows) (Trung cấp) tổng lớn nhất trong hình thoi bán kính trên lưới : cùng bài toán với chương trình lưới xoay ở trên (lưới xoay cạnh ), nhưng phải sửa phần đọc input vì đề cho
N Krồi lưới , còn chương trình đọcn m k: đọc , rồi đặt . - Dãy con Manhattan (manhsub) (Nâng cao) dùng tính chất "nằm giữa" theo Manhattan: bộ ba xấu với các điểm chính là ba phần tử tạo thành dãy con đơn điệu không chặt (không giảm hoặc không tăng, vì giá trị bằng nhau cũng xấu), từ đó suy ra đoạn tốt rất ngắn.
- Bò Lười (Gold) (lazycowg) (Kỳ cựu) tâm được đặt tùy ý: xoay 45 độ để hình thoi thành hình vuông cạnh , rồi tìm vị trí hình vuông phủ tổng lớn nhất bằng quét cửa sổ theo và cây phân đoạn theo .
- Tam Giác Đều Manhattan (triangles) (Bậc thầy) sau khi xoay, trong mọi tam giác đều Manhattan luôn có hai đỉnh cùng hoặc cùng ; cố định cặp đó rồi đếm đỉnh thứ ba bằng tổng tiền tố dọc các đường chéo.
Đề VOI
- Trại bò tót (voi16_rbull) (Kỳ cựu) VOI 2016: với tâm cố định, bán kính càng lớn thì càng dễ vi phạm, nên mỗi tâm chỉ cần bán kính hợp lệ lớn nhất; hãy nghĩ xem bán kính đó liên hệ thế nào với khoảng cách Manhattan tới "những cọc gây rắc rối" (tính cho mọi ô cùng lúc), còn việc đếm cọc trong hình thoi là truy vấn hình vuông trên lưới xoay.
- Kết nối internet (voi22_inet) (Kỳ cựu) VOI 2022: hãy nghĩ tới cây khung nhỏ nhất của đồ thị đầy đủ với trọng số là khoảng cách Manhattan; đồ thị này có cạnh nên cần cách giảm số cạnh ứng viên như ở mục MST Manhattan phía trên.
- Năng lượng tối thiểu (voi23_robot) (Chuyên gia) VOI 2023: kỹ thuật trên trang này chỉ là một phần của lời giải. Số bước trên sân không vật cản chính là khoảng cách Manhattan (BFS đa nguồn chỉ đủ cho subtask sân ngắn); cố định dòng rồi tách thành phần theo dòng cộng phần tuyến tính theo cột, phần khó còn lại là cập nhật cục bộ khi thêm, bớt trạm.
Bình luận