# 題目

AP325 Q-5-5. Closest pair

# 解題思路

這題很多假解要小心

假解 1
我在 judge 網站上看到的
上面測資強度不構被他混過去了

#include <bits/stdc++.h>
using namespace std;
struct POINT{
    int x;
    int y;
    bool operator < (POINT b){
        if (x != b.x) return x < b.x;
        else return y < b.y;
    }
};
POINT p[100005];
int n;
int min_d = 200000001;
int minDaC(int l, int r)
{
    int d, m;
    if (l >= r) return min_d;
    m = (l + r) / 2;
    
    d = min(minDaC(l, m), minDaC(m+1, r));
    for (int i=m+1; p[i].x-p[m].x < d && i<=r; i++){
        int dy = abs(p[i].y - p[m].y);
        if (dy < d)
            d = min(d, (abs(p[i].x - p[m].x) + dy));
    }
    for (int i=m; p[m+1].x-p[i].x < d && i>=l; i--){
        int dy = abs(p[m+1].y - p[i].y);
        if (dy < d)
            d = min(d, (abs(p[m+1].x - p[i].x) + dy));
    }    
    
    return d;
}
int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    for (int i=1; i<=n; i++)
        cin >> p[i].x >> p[i].y;
    sort(p+1, p+1+n);
    // cout << endl;
    // for (int i=1; i<=n; i++)
    //     cout << p[i].x << ' ' << p[i].y << endl;
    // cout << endl;
    cout << minDaC(1, n) << endl;
    return 0;
}

TLE 解 2

這邊是沒考慮到 y 座標
所以 x 擠在一起會掃到 [mid-d,mid+d] 線內的所有點,退化成 O (n^2 * logn)
極端測資會 TLE

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define Rabbir_Reaper ios::sync_with_stdio(0);cin.tie(0);
const int INF = 1LL << 60;
vector<pair<int, int>> v;
int dist(const pair<int, int> &a, const pair<int, int> &b){
    return abs(a.first - b.first) + abs(a.second - b.second);
}
int solve(int l, int r){
    if (r-l == 1) return INF;
    int mid = (l + r) >> 1;
    int xmid = v[mid].first;
    int d = min(solve(l, mid), solve(mid, r));
    // 找到 x 值在 [xmid - d, xmid + d] 範圍內的點
    int low = lower_bound(v.begin() + l, v.begin() + r, make_pair(xmid - d, LLONG_MAX)) - v.begin();
    int high = lower_bound(v.begin() + l, v.begin() + r, make_pair(xmid + d, LLONG_MIN)) - v.begin();
    for (int i = low; i < high; i++){
        for (int j = i + 1; j < high && (v[j].first - v[i].first) < d; j++){
            d = min(d, dist(v[i], v[j]));
        }
    }
    return d;
}
signed main(){
    Rabbir_Reaper
    int n;
    cin >> n;
    v.resize(n);
    for (int i = 0; i < n; i++){
        cin >> v[i].first >> v[i].second;
    }
    sort(v.begin(), v.end());
    cout << solve(0, n);
    return 0;
}

# 程式碼

#include <bits/stdc++.h>
using namespace std;
#define Rabbir_Reaper ios::sync_with_stdio(0),cin.tie(0);
#define int long long
const int INF = 1LL << 60;
vector<pair<int, int>> v;
int dist(const pair<int, int> &a, const pair<int, int> &b){
    return abs(a.first - b.first) + abs(a.second - b.second);
}
int solve(int l, int r){
    if(r-l == 1) return INF;
    int mid = (l + r) >> 1;
    int xmid = v[mid].first;
    int d = min(solve(l, mid), solve(mid, r));
    vector<pair<int,int>> strip;
    for (int i = l; i < r; i++){
        if (abs(v[i].first - xmid) < d)
            strip.push_back(v[i]);
    }
    
    sort(strip.begin(), strip.end(), [](const pair<int, int> &a, const pair<int, int> &b){
        return a.second < b.second;
    });
    // 掃描最近的 7 個點
    for(int i = 0; i < strip.size(); i++){
        for(int j = i + 1; j < strip.size() && (strip[j].second - strip[i].second) < d; j++){
            d = min(d, dist(strip[i], strip[j]));
        }
    }
    return d;
}
signed main(){
    Rabbir_Reaper
    int n;
    cin >> n;
    v.resize(n);
    for (int i = 0; i < n; i++){
        cin >> v[i].first >> v[i].second;
    }
    sort(v.begin(), v.end());
    cout << solve(0, n) << "\n";
    return 0;
}
更新於 閱讀次數 次