hdu 1007 平面最近点对  随机增量…

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1007

 

题目大意:求平面内最近点对的距离

 

考查点:求平面最近点对的较快算法,(二分或随机增量)

 

思路:当我们确定了一个两点之间的距离r以后,就可以在平面上画出一个正方形表格来

正方形的边长为r,这样可能与点x更新r的点只能在x所在点的8个方向及自己所在格子。

这样我们就可以将问题的规模缩小,每次只看某个点周围的几个就行,记录每个格子里有哪些点就会用到hash记录, 这里我是用了(I × MAXN +  j %(素数),效果可能不是很强,算法思路是:现将数据随机化,然后枚举每个点,判断此点是否能更新当前的距离,若能则更改r并且从新绘制表格,若不能更新r则将此点放入方格中。

算法时间复杂度O(n * k/n * n) = O(kn) 常数较大的线性时间算法。

 

提交情况:runtime error   7 原因忘记考虑坐标是负数的情况

                     Time limit exceeded  1 原因负数情况处理错误

               Accepted  1

 

经验: 考虑问题要全面,hash要写的尽量使宽裕的感觉

 

收获: 体会了增量f法的魔力

 

AC code

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#include <string.h>

#include <math.h>

 

#define MAXN 101000

#define DUBF 9999999.9

#define INF 130589

 

struct NODE{

    int to;

    int next;

};

 

struct NODE1{

    double x, y;

};

intdirection[9][2] = {0, 0, -1, -1, -1, 0, -1, 1, 0, 1, 1, 1, 1, 0, 1, -1, 0, -1};

 

NODE1 point[MAXN];

NODE edges[MAXN];

int ad;

intmap[INF];

 

 

int HASH(int x, int y){

    return ((x * MAXN + y) % INF + INF) % INF;

}

 

double len(int i, int j){

    return sqrt((point[i].x - point[j].x) * (point[i].x - point[j].x) + (point[i].y - point[j].y) * (point[i].y - point[j].y));

}

 

void Into_Hash(int i, double r){

    edges[ad].to = i;

    edges[ad].next = map[HASH( (int)(point[i].x/r), (int)(point[i].y/r) )];

    map[HASH( (int)(point[i].x/r), (int)(point[i].y/r) )] = ad ++;

}

 

voidRenew_Hash(int n, double r){

    ad = 0;

    memset(map, -1, sizeof(map));

    for(int i = 0; i <= n; i ++)

       Into_Hash(i, r);

}

 

doubleGet_len_around(int p, double r){

    int x = (int) (point[p].x / r), y = (int) (point[p].y / r), i, j;

    double s = DUBF;

    for(int k = 0; k < 9; k ++){

       i = x + direction[k][0], j = y + direction[k][1];

       for(int q = map[HASH(i, j)]; ~q; q = edges[q].next)

           s = s < len(edges[q].to, p) ? s : len(edges[q].to, p);

    }

    return s;

}

 

double Get_R(int n){

    double r = len(0 , 1), s;

    int i;

    if(r - 0 < 1e-6 || n < 2) return 0;

    Renew_Hash(1, r);

    for(i = 2; i < n; i ++)

       if((s = Get_len_around(i, r)) < r){

           r = s;

           if(r - 0 < 1e-6) return 0;

           Renew_Hash(i, r);

       }

       else

           Into_Hash(i, r);

    return r;

}

 

void swap(int i, int j){

    NODE1 t = point[i];

    point[i] = point[j];

    point[j] = t;

}

 

int main(){

    int n, i;

    while(~scanf("%d", &n), n){

       for(i = 0; i < n; i ++) scanf("%lf %lf", &point[i].x, &point[i].y);

       srand((unsigned)time(NULL));

       for(i = 0; i < n; i ++) swap(i, rand() % n);

       printf("%.2lf\n", Get_R(n) / 2);

    }

    return 0;

}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值