hdu 1007 Quoit Design(分治法)

题目链接: hdu 1007 Quoit Design
题目描述: 在坐标中给出几个点,求出距离最短的两个点的距离的一半。
题解思路: 用分而治之的方法
1、把每个点的横坐标按从大到小的排列顺序排序,然后根据左右L,R边界,分成两个小规模的问题求出左半部分的最小值和右半部分的最小值 ,然后取两者之中的最小d。
2、因为完成第一步后还存在着跨区间的两个点的距离可能更小,所有要先针对纵坐标进行排序,然后看是否有跨区跨区间的点是否更小,这里要有一个剪枝,就是找到离分治的中间的的点的距离小于第一步求的d的点才有资格去再次参与计算。然后综合左右各半部分的最小和跨区间的最下就可以求到所有点的最小值。
3、上面的就是分治的基本思路已经出来了,这样递归的基本样子就可以出来了,还差的就是递归基,我们分治的时候每次都是分成两小规模问题,那么就存在一个mid分界点,而最小可以直接求的子问题是当一个区间只有两个数的时候就可以直接求解,但是还有存在三个点的时候,不可再分,所有三个点也是一个递归基。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef struct node {
    double x, y;
}point;
bool cmp1(point a, point b) {
    return a.x < b.x;
}
bool cmp2(point a, point b) {
    return a.y < b.y;
}
point p[100005];
point p1[100005];

double dis(point a, point b) {
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double slove(int l, int r)
{
    double d;
    if (r - l == 1) {
        return dis(p[l], p[r]);
    }
    if (r - l == 2) {
        double temp = dis(p[l], p[l + 1]); 
        double temp1 = min(temp, dis(p[l], p[r]));
        return min(temp1, dis(p[l + 1], p[r]));
    }
    else {
        int mid = (l + r) / 2;
        d = min(slove(l, mid), slove(mid + 1, r));
        int cnt = 0;
        for (int i = l; i <= r; i++) {
            if (fabs(p[i].x - p[mid].x) < d) {
                p1[cnt++] = p[i];
            }
        }
        sort(p1, p1 + cnt, cmp2);
        for (int i = 0; i < cnt; i++) {
            for (int j = i + 1; j < cnt; j++) {
                if (p1[j].y - p1[i].y > d) {
                    break;
                }
                else {
                    d = min(d, dis(p1[j], p1[i]));
                }
            }
        }
    }
    return d;
}
int main()
{
    int n;
    while (1) {
        scanf("%d", &n);
        if (n == 0) {
            break;
        }
        for (int i = 0; i < n; i++) {
            scanf("%lf%lf", &p[i].x, &p[i].y);
        }
        sort(p, p + n, cmp1);
        double ans = slove(0, n - 1);
        printf("%.2f\n", ans / 2);
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值