【分治】hdu 1007
来源:互联网 发布:外文文献数据库 编辑:程序博客网 时间:2024/06/08 02:49
经典例题,平面最接近点对
题目
在一个二维平面上,有n个点,现在问最接近的两个点的距离是多少
思路
本来最近在练kd树的,想着上来就套个kd树。
但是很神奇的是kd树也给卡掉了。kd树的建树时间是O(nlogn) ,二维的查询时间是O(n∗(√n))
然后愉快的给卡数据量了orz。
刚好在上算法课,就写一下分治咯。分治的思想:
对于平面上的点,我们先按照x轴给他们排序,从大问题划分成小问题。
当要比较的点小于等于三个的时候,直接暴力计算即可。
归并回来时,取左右区间的最小值。
那把两边合并后也会有点可以构造出较短的线段。那当点数多的时候怎么办呢?
如果比较的点数可以使常数个的话,那就用不到O(n2) 了对吧。
7次比较定理:
对于一个点,假设最短距离为d的时候,他在某点构成的图是这样的。
那么我们只要证明如果有一点他在中线上,那最多只要跟7个点进行比较即可。
这里就不作几何了,我们不难发现,在2 * d * d的矩阵中,我们最多能发现有8个点他们两两之间距离不小于d
所以我们只需要划分一下中点左右界限为d的点集,再每次以高度为d的矩形来进行里面块的比较。
我们可以发现,一开始排序的时候按照x排序,分治完毕后,x轴好像并没有什么用了,我们可以想到归并排序,回溯的时候将y轴就顺带排序了。
下面给上代码:
/*@resource: hdu 1007@data: 2017-10-02@author: QuanQqqqq@algorithm: 分治*/#include <bits/stdc++.h>#define MAXN 100005#define INF (1LL << 30)using namespace std;struct Point { double x, y; bool operator < (const Point &a) const { return x < a.x; }} pts[MAXN], tps[MAXN], ytps[MAXN];double sqr(double x) { return x * x;}int cmpY(Point a, Point b) { return a.y < b.y;}double getDis(Point a, Point b) { return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));}double findMinDisPoint(int L, int R) { double ret = INF; if (R - L <= 2) { for (int i = L; i <= R; i++) { for (int j = i + 1; j <= R; j++) { ret = min(ret, getDis(pts[i], pts[j])); } ytps[i] = pts[i]; } //这里为了方便,只有三个数排序,依然是常数的时间复杂度 sort(ytps + L, ytps + R + 1, cmpY); return ret; } int MID = L + R >> 1; double DL = findMinDisPoint(L, MID); double DR = findMinDisPoint(MID + 1, R); double d = min(DL, DR); ret = min(ret, d); //这里进行归并排序 int idx = L, idxL = L, idxR = MID + 1; while (idxL <= MID && idxR <= R) { if (ytps[idxL].y <= ytps[idxR].y) { tps[idx++] = ytps[idxL++]; } else { tps[idx++] = ytps[idxR++]; } } while (idxL <= MID) { tps[idx++] = ytps[idxL++]; } while (idxR <= R) { tps[idx++] = ytps[idxR++]; } for (int i = L; i <= R; i++) { ytps[i] = tps[i]; } //这里将距离大于的点筛除 int cnt = 0; for (int i = L; i <= R; i++) { if (abs(ytps[i].x - ytps[MID].x) <= d) { tps[cnt++] = ytps[i]; } } for (int i = 0; i < cnt; i++) { for (int j = i + 1; j < cnt && abs(tps[j].y - tps[i].y) < d; j++) { ret = min(ret, getDis(tps[i], tps[j])); } } return ret;}int main() { int n; while (~scanf("%d", &n) && n) { for (int i = 0; i < n; i++) { scanf("%lf %lf", &pts[i].x, &pts[i].y); } sort(pts, pts + n); printf("%.2lf\n", findMinDisPoint(0, n - 1) / 2); }}
再。弱弱的送上tle多次的kd树,如果有dalao能帮忙就评论下呗。
/*@resource: hdu 1007@data: 2017-09-29@author: QuanQqqqq@algorithm: kd树*/#include <math.h>#include <algorithm>#include <stdio.h>#define MAXN 100005#define lson l, mid - 1, root << 1#define rson mid + 1, r, root << 1 | 1#define ll long longusing namespace std;int idx, m;struct node { double f[3]; int id; bool operator < (const node &a) const { return f[idx] < a.f[idx]; }} kd[MAXN << 2], data[MAXN];int flag[MAXN << 2];pair<double, node> res;void build(int l, int r, int root, int dep) { if (l > r) { return ; } flag[root] = 1; flag[root << 1] = flag[root << 1 | 1] = -1; idx = dep % m; int mid = l + r >> 1; nth_element(data + l, data + mid, data + r + 1); kd[root] = data[mid]; build(lson, dep + 1); build(rson, dep + 1);}double sqr(double x) { return x * x;}double getDis(node a, node b) { return sqr(a.f[0] - b.f[0]) + sqr(a.f[1] - b.f[1]);}void query(node que, int root, int dep) { if (flag[root] == -1) { return ; } int x = root << 1; int y = root << 1 | 1; int idm = dep % 2; if (que.f[idm] >= kd[root].f[idm]) { swap(x, y); } if (~flag[x]) { query(que, x, dep + 1); } pair<double, node> cur = make_pair(getDis(que, kd[root]), kd[root]); bool mark = false; if (res.first == -1) { if (que.id != cur.second.id) { res.first = cur.first; res.second = cur.second; } mark = true; } else { if (cur.first < res.first && que.id != cur.second.id) { res.first = cur.first; res.second = cur.second; } //如果发现有可能作为最短距离进入看一下 if (sqr(kd[root].f[idm] - que.f[idm]) < res.first) { mark = true; } } if (mark && ~flag[y]) { query(que, y, dep + 1); }}int main() { int T, n, q; m = 2; while (~scanf("%d", &n) && n) { for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { scanf("%lf", &data[i].f[j]); } data[i].id = i; } build(0, n - 1, 1, 0); res.first = -1; for (int i = 0; i < n; i++) { res.second = data[i]; query(data[i], 1, 0); } printf("%.2lf\n", sqrt(res.first) / 2); } // system("pause");}
阅读全文
0 0
- hdu 1007 分治
- hdu 1007 (分治)
- 【分治】hdu 1007
- Quoit Design - HDU 1007 分治
- hdu 1007(分治法应用)
- HDU 1007 (分治递归)
- HDU 1007 Quoit Design 分治
- hdu 1007 Quoit Design(分治法)
- HDU 1007 Quoit Design 分治法
- HDU 1007 Quoit Design (分治)
- hdu 1007 平面上的分治
- 分治 hdu 1007 最近点问题
- hdu 1007 Quoit Design(平面分治)
- HDU 1007 Quoit Design竟然要分治
- HDU 1007 Quoit Design(分治)
- hdu 1007 平面最近点对 分治
- hdu 1007 最近点对-分治法
- HDU 1007 Quoit Design(分治)
- Spring Cache抽象-基于XML的配置声明(基于EhCache的配置)
- 关于Ubuntu中Could not get lock /var/lib/dpkg/lock解决方案
- springmvc简单整合beetl
- GRASP模式
- POJ 2774 Long Long Message 后缀数组求最长公共子串
- 【分治】hdu 1007
- Python3的sys模块函数
- 华裔科学家及丈夫成Nobel医学奖热门人选
- 一起学Netty(二十)netty的比较规范的C/S端的写法
- Objective-C学习笔记(一)
- HDU 1199 Color the Ball(离散化入门+非线段树做法)
- leetcode 002 Add Two Numbers
- ubuntu安装laravel/homestead
- Lvs+keepalived实现高可用负载均衡