这道题目有两种方法:
一种是蛮力法,就是通过双层循环来求得最近点对。优点是思维简单,实现简单。但是时间用太多。由于要进行n(n-1)/2次运算,所以时间复杂度为O(N^2)。而这道题目的N是2 <= N <= 100,000 。显然会超时。但是,我还是作死的把代码写出来了。所以RUNTIME ERROR……
代码如下:(如果N不大时可以参考下)
#include <iostream> #include <cmath> using namespace std; typedef struct node { double x; double y; }point; double count(point p1,point p2) { return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y))/2; } point p[100001]; int main() { int n,r; double min,temp; while(cin>>n&&n) { for(int i=0;i<n;i++) cin>>p[i].x>>p[i].y; min=count(p[0],p[1]); for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++){ temp=count(p[i],p[j]); if(min>temp) min=temp;} } printf("%.2lf\n",min); } return 0; }
现在就是要考虑怎么AC的问题了。理论方法请参见http://blog.youkuaiyun.com/zhuangjingyang/article/details/37312089
用分治思想,把大问题化小,其中那个6个点是本算法的一个精髓所在。(虽然有点不可思议。但是通过反证法确实如此)
以下代码为参见网上所修改。加了些注释较好理解
#include <iostream> #include <cstdio> #include <string> #include <algorithm> //sort 函数 #include <cmath> using namespace std; typedef struct node { double x; double y; }point; point p[100001]; point y[100001]; int cmp_x(point a, point b) { return a.x < b.x; } int cmp_y(point a, point b) { return a.y < b.y; } double dist(point a, point b) { return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)); } double find_near(int l, int r) { if (r - l == 1) //只有两个点直接返回结果 return dist(p[l], p[r]); if (r - l == 2) //三个点时也返回结果 return min(min(dist(p[l], p[l+1]), dist(p[l+1], p[l+2])), dist(p[l], p[l+2]));//三个点 查询返回 int mid = (l+r) / 2; double curmin = min(find_near(l, mid), find_near(mid+1, r)); //递归查询 int ith = 0; int i,j; for (i = l; i <= r; i++) { if (p[mid].x - p[i].x <= curmin || p[i].x - p[mid].x <= curmin) //查询在curmin范围内的点 y[ith++] = p[i]; } sort(y, y + ith, cmp_y); //之后只要查询y与p最短的即可 int num; for (i = 0; i < ith; ++i) for (j = i+1, num = 0; j < ith && num < 7; ++num, ++j) //6个点 算法精髓所在 if ( dist(y[i], y[j]) < curmin ) curmin = dist(y[i], y[j]); else break; return curmin; } int main() { int n; while (cin >> n && n) { int i; for (i = 0; i < n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y); sort(p, p+n, cmp_x); printf("%.2lf\n", find_near(0, n-1)/2); } return 0; }
总结:分治思想,在编程中是经常出现的一种思想。常常说,递归是一种不是很理想的方法。因为其效率低下。但是恰当的使用递归却是非常巧妙的。就比如在分治思想中。所以,有关这样的题目以后更是要多加练习!
HDOJ 1007 Quoit Design
最新推荐文章于 2021-02-22 21:54:51 发布