HDOJ 1007 Quoit Design (最近點對+分治)

原題鏈接

一、題目描述

Problem Description
Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded.
In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a configuration of the field, you are supposed to find the radius of such a ring.

Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered to be 0.
 

Input
The input consists of several test cases. For each case, the first line contains an integer N (2 <= N <= 100,000), the total number of toys in the field. Then N lines follow, each contains a pair of (x, y) which are the coordinates of a toy. The input is terminated by N = 0.
 

Output
For each test case, print in one line the radius of the ring required by the Cyberground manager, accurate up to 2 decimal places. 
 

Sample Input
2 0 0 1 1 2 1 1 1 1 3 -1.5 0 0 0 0 1.5 0
 

Sample Output
0.71 0.00 0.75

二、題目分析

題目要求套圈的最大半徑,而這個套圈每次只能套一個toy。所以,題目轉化爲求平面中最近的兩個toy之間的距離。也就是最近點對的問題。

1,暴力解法

求n個點中最近的兩個點,共C(n, 2)中匹配,時間複雜度O(n^2).

2,分治

1)讀取點橫縱座標數據,並將點按橫座標升序排列。

2)以中間點爲基準,將平面內的點分爲左右兩個部分。此時,最近點對可能出現在左部分、右部分或者一點在左部分,一點在右部分,共三種情況。

3)求出這三部分的最近點對,取最小值。


對於左右部分的最近點對可以遞歸求解,然後取較小值mini。

對於一點在左部分,一點在右部分的情況,可以有下面兩種處理方式。

a、取點集中橫座標與分界線的距離小於mini的點存入p2數組中,對p2數組按縱座標進行排序。計算p2數組中點對的距離,不斷和mini比較。

b、取點集中橫座標與分界線的距離小於mini的點存入pl, pr兩個數組中,在分界線左邊的放在pl中,否則放在pr中。然後在兩個數組中尋找最近點對,和mini比較。


三、AC代碼

a

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0X3F3F3F3F;
struct Point{
    double x;
    double y;
} p1[100001], p2[100001];

bool cmp_x(Point p1, Point p2) {
    return p1.x < p2.x;
}

bool cmp_y(Point p1, Point p2) {
    return p1.y < p2.y;
}

double square(double x) {
    return x*x;
}

double dist(Point p1, Point p2) {
    return sqrt(square(p1.x-p2.x) + square(p1.y-p2.y));
}

double search_nst(int l, int r) {
    if(l == r) return INF;
    if(l+1 == r) return dist(p1[l], p1[r]);
    int mid = (l+r)/2;
    double mini = min(search_nst(l, mid), search_nst(mid+1, r));
    int k = 0;
    for(int i = l; i <= r; i++) {
        if(fabs(p1[i].x - p1[mid].x) < mini) p2[k++] = p1[i];
    }
    sort(p2, p2+k, cmp_y);
    for(int i = 0; i < k; i++) {
        for(int j = i+1; j < k && (p2[j].y-p2[i].y) < mini; j++) {
            if(dist(p2[i], p2[j]) < mini) mini = dist(p2[i], p2[j]);
        }
    }
    return mini;
}

int main() {
    int N;
    while(cin >> N && N) {
        for(int i = 0; i < N; i++) {
            cin >> p1[i].x >> p1[i].y;
        }
        sort(p1, p1+N, cmp_x);
        double ans = search_nst(0, N-1);
        printf("%.2lf\n", ans/2.0);
    }
}


b(在HDOJ上AC, 在牛客網上沒有通過所有用例)

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0X3F3F3F3F;
struct Point{
    double x;
    double y;
} p1[100001], pl[100001], pr[100001];

bool cmp_x(Point p1, Point p2) {
    return p1.x < p2.x;
}

bool cmp_y(Point p1, Point p2) {
    return p1.y < p2.y;
}

double square(double x) {
    return x*x;
}

double dist(Point p1, Point p2) {
    return sqrt(square(p1.x-p2.x) + square(p1.y-p2.y));
}

double search_nst(int l, int r) {
    if(l == r) return INF;
    if(l+1 == r) return dist(p1[l], p1[r]);
    int mid = (l+r)/2;
    double mini = min(search_nst(l, mid), search_nst(mid+1, r));
    int k1 = 0, k2 = 0;
    for(int i = l; i <= r; i++) {
        if(fabs(p1[i].x - p1[mid].x) < mini) {
            if(p1[i].x -p1[mid].x < 0) pl[k1++] = p1[i];
            else pr[k2++] = p1[i];
        }
    }

    for(int i = 0; i < k1; i++) {
        for(int j = 0; j < k2; j++) {
            double tmpDist = dist(pl[i], pr[j]);
            if(tmpDist < mini) mini = tmpDist;
        }
    }

    return mini;
}

int main() {
    int N;
    while(scanf("%d", &N) != EOF && N) {
        for(int i = 0; i < N; i++) {
            //cin >> p1[i].x >> p1[i].y;
            scanf("%lf%lf", &p1[i].x, &p1[i].y);
        }
        sort(p1, p1+N, cmp_x);
        double ans = search_nst(0, N-1);
        printf("%.2lf\n", ans/2.0);
    }
}



發佈了40 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章