Hướng dẫn giải của Khoảng cách xa nhất


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Lời giải này đang bị ẩn cho đến khi bạn chọn mở ra.

Chúng tôi khuyên bạn nên tự thử giải bài trước. Việc mở lời giải có thể làm lộ mất ý tưởng chính trước khi bạn có cơ hội tự giải.

Bạn phải đăng nhập để mở lời giải này.

Đăng nhập

Tác giả: Hiếu Nguyễn, duongvunhatminh, 2uockhanh29, Namdo

Editorial for mdist: Khoảng cách xa nhất

Hiểu bài toán

Bài toán yêu cầu tìm khoảng cách Manhattan lớn nhất giữa hai điểm bất kỳ trong N điểm cho trước. Khoảng cách Manhattan giữa hai điểm (x1, y1) và (x2, y2) được định nghĩa là |x1 - x2| + |y1 - y2|. Với N tối đa là 100, ta cần tìm giá trị lớn nhất của biểu thức này trong tất cả các cặp điểm.

Các cách tiếp cận

Cách Brute Force (Lặp kép)
#include <stdio.h>
#include <math.h>

int main() {
    int n;
    scanf("%d", &n);
    int x[105], y[105];
    for (int i = 0; i < n; i++) {
        scanf("%d %d", &x[i], &y[i]);
    }
    int max_dist = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int dist = abs(x[i] - x[j]) + abs(y[i] - y[j]);
            if (dist > max_dist) {
                max_dist = dist;
            }
        }
    }
    printf("%d", max_dist);
    return 0;
}
  • Time Complexity: O(N^2)
  • Space Complexity: O(N)

Đây là cách tiếp cận trực tiếp nhất. Ta duyệt qua tất cả các cặp điểm (i, j) với i < j để tránh tính toán trùng lặp. Với mỗi cặp, ta tính khoảng cách Manhattan và cập nhật giá trị lớn nhất. Với N <= 100, số lượng cặp là khoảng 5000, hoàn toàn chấp nhận được trong thời gian chạy.

Cách Optimized (Tối ưu hóa Manhattan)
#include <stdio.h>
#include <limits.h>
#include <math.h>

int main() {
    int n;
    scanf("%d", &n);
    int min_sum = INT_MAX, max_sum = INT_MIN;
    int min_diff = INT_MAX, max_diff = INT_MIN;

    for (int i = 0; i < n; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        // Biến đổi tọa độ
        // P1: (x + y)
        // P2: (x - y)
        if (x + y < min_sum) min_sum = x + y;
        if (x + y > max_sum) max_sum = x + y;
        if (x - y < min_diff) min_diff = x - y;
        if (x - y > max_diff) max_diff = x - y;
    }

    int dist1 = max_sum - min_sum;
    int dist2 = max_diff - min_diff;

    if (dist1 > dist2) printf("%d", dist1);
    else printf("%d", dist2);

    return 0;
}
  • Time Complexity: O(N)
  • Space Complexity: O(1)

Cách tiếp cận này sử dụng tính chất của khoảng cách Manhattan. Ta có thể biến đổi công thức: |x1 - x2| + |y1 - y2| = max( |(x1+y1) - (x2+y2)|, |(x1-y1) - (x2-y2)| ). Do đó, thay vì xét tất cả cặp điểm, ta chỉ cần tìm giá trị lớn nhất và nhỏ nhất của (x+y) và (x-y). Khoảng cách lớn nhất sẽ là hiệu giữa giá trị lớn nhất và nhỏ nhất của một trong hai biến đổi này. Độ phức tạp giảm từ O(N^2) xuống O(N).

Phân tích độ phức tạp

Cách tiếp cận Time Space Tên
1 O(N^2) O(N) Brute Force (Lặp kép)
2 O(N) O(1) Optimized (Tối ưu hóa Manhattan)

Bài học kinh nghiệm

  • Khoảng cách Manhattan giữa hai điểm có thể được biểu diễn qua các hàm max của các hiệu tọa độ biến đổi.
  • Với N nhỏ (<= 100), giải thuật O(N^2) hoàn toàn khả thi và dễ implement.

Lỗi thường gặp

  • Quên sử dụng hàm abs() khi tính hiệu, dẫn đến kết quả âm sai lệch.
  • Khởi tạo biến max ban đầu sai (ví dụ bằng 0 thay vì -1 hoặc giá trị của cặp đầu tiên) có thể sai nếu tất cả khoảng cách đều nhỏ hơn 0 (trong bài này khoảng cách luôn >= 0 nên 0 là an toàn, nhưng logic chung nên cẩn thận).
  • Biến đổi công thức |x1 - x2| + |y1 - y2| = max(|(x1+y1)-(x2+y2)|, |(x1-y1)-(x2-y2)|) là một kiến thức hữu ích nhưng với N nhỏ thì vòng lặp kép đơn giản và ít lỗi hơn.

Bình luận

Please read the guidelines before commenting.


Không có bình luận tại thời điểm này.