題目: UVa - 10245 - The Closest Pair Problem

題目說明

給一些在二維平面上的點,求最近的兩點距離為何。

Input: 每組測資第一個整數 N,表示有幾個點 ( 若 N 為 0 表結束 ),後面 N 行每行有兩個整數,表點的座標。

Output: 輸出最近的兩點距離為何,輸出至小數點後四位,若超過 10000 則輸出 "INFINITY"

解題思路

Closet Pair Problem,可用 Sweep line 或 Divide and Conquer。

參考解法

Sweep line:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <bits/stdc++.h>

using namespace std;

#define FOR(i, a, b) for (int i = a; i < b; ++i)
#define CLR(c) memset(c, 0, sizeof(c))

static auto __ = []
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
return 0;
}();

// reference: https://ppt.cc/f4Uwtx

const int INF = (int)1e9;
const int MXN = 10000;

struct Point
{
double x;
double y;
};

int N;
Point P[MXN];

double dist(const Point& l, const Point& r)
{
return sqrt(pow(r.x - l.x, 2) + pow(r.y - l.y, 2));
}

void read()
{
FOR(i, 0, N) cin >> P[i].x >> P[i].y;
}

void solve()
{
// sweep line
sort(P, P + N, [](Point& l, Point& r) { return l.x < r.x; });

double d = 1e4;
FOR(i, 0, N) FOR(j, i + 1, N)
{
if (P[i].x + d < P[j].x) break; // 若區域內沒有點則不需要再判斷
d = min(dist(P[i], P[j]), d);
}

if (d == 1e4) cout << "INFINITY\n";
else cout << setprecision(4) << fixed << d << '\n';
}

int main()
{
while (cin >> N && N)
{
read();
solve();
}
}

Divide and Conquer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <bits/stdc++.h>

using namespace std;

#define FOR(i, a, b) for (int i = a; i < b; ++i)
#define CLR(c) memset(c, 0, sizeof(c))

static auto __ = []
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
return 0;
}();

// reference: https://ppt.cc/f4Uwtx

const int INF = (int)1e9;
const int MXN = 10000;

struct Point
{
double x;
double y;
};

Point P[MXN];
Point tmp[MXN];

int N;

double dist(const Point& l, const Point& r)
{
return sqrt(pow(l.x - r.x, 2) + pow(l.y - r.y, 2));
}

bool cmp1(const Point& l, const Point& r)
{
return l.x < r.x;
}

bool cmp2(const Point& l, const Point& r)
{
return l.y < r.y;
}

void read()
{
FOR(i, 0, N) cin >> P[i].x >> P[i].y;
}

double DnC(int L, int R)
{
if (L >= R) return INF;

auto M = (L + R) / 2;
auto d = min(DnC(L, M), DnC(M + 1, R));

int idx = 0;
for (int i = M; i >= L && P[M].x - P[i].x < d; --i) tmp[idx++] = P[i];
for (int i = M + 1; i <= R && P[i].x - P[M].x < d; ++i) tmp[idx++] = P[i];

sort(tmp, tmp + idx, cmp2);

FOR(i, 0, idx) FOR(j, 1, 4 && i + j < idx) d = min(dist(tmp[i], tmp[i + j]), d);

return d;
}

void solve()
{
sort(P, P + N, cmp1);
auto ret = DnC(0, N - 1);
if (ret >= 1e4) cout << "INFINITY\n";
else cout << setprecision(4) << fixed << ret << '\n';
}

int main()
{
while (cin >> N && N)
{
read();
solve();
}
}

參考資料

UVa 10245 - The Closest Pair Problem | NaiveRed&’s Blog
UVa 10245 - The Closest Pair Problem_小白菜又菜-CSDN博客