(洛谷 P1429 平面最近点对(加强版) || 洛谷 P1257 || Quoit Design HDU - 1007 ) && Raid POJ - 3714
这个讲的好:
分治法
先空着
看一下这个第三个方法(随机增量哈希,O(n))
1.千万不要用unordered_map/hash_map!T飞是肯定的;要手写哈希表,所以码量就很大;手写哈希表方法记一下
2.事实上以d为边长画格子,每次遍历相邻的9个格子,常数要比以d/2边长画格子,每次遍历相邻25个格子要好(当然此时每个格子里面不一定只有一个数了);不知道为什么
3.注意,用此方法时,如果距离已经为0了,那么就马上跳出循环(不然可能由于除以0或很接近0的数产生非常大的格子编号,产生不好的事情)
4.常数似乎较大,比一些分治法要慢
别人的代码!跑的飞快(交洛谷)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
#define MAXN 201000
#define DUBF 999999999.9
#define INF 201007
struct NODE
{
int to;
int next;
};
struct NODE1
{
double x, y;
};
int direction[][] = {, , -, -, -, , -, , , , , , , , , -, , -};
NODE1 point[MAXN];
NODE edges[MAXN];
int ad;
int map[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 ++;
}
void Renew_Hash(int n, double r)
{
ad = ;
memset(map, -, sizeof(map));
for(int i = ; i <= n; i ++)
Into_Hash(i, r);
}
double Get_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 = ; k < ; k ++)
{
i = x + direction[k][], j = y + direction[k][];
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(, ), s;
int i;
if(r - < 1e- || n < )
return ;
Renew_Hash(, r);
for(i = ; i < n; i ++)
if((s = Get_len_around(i, r)) < r)
{
r = s;
if(r - < 1e-)
return ;
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)==)
{
for(i = ; i < n; i ++)
scanf("%lf %lf", &point[i].x, &point[i].y);
srand((unsigned)time(NULL));
for(i = ; i < n; i ++)
swap(i, rand() % n);
printf("%.4lf\n", Get_R(n));
}
return ; }
自己的代码(跑的慢不少,找不出来原因)(交洛谷)
#pragma GCC optimize("Ofast")
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<ctime>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef unsigned ul;
typedef pair<ul,ul> puu;
struct P
{
double x,y;
P():x(),y(){}
P(double a,double b):x(a),y(b){}
}p[];
double sqr(double x){return x*x;}
double dis(const P &a,const P &b)
{
return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
//int dx[]={-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,};
//int dy[]={-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,};
int dx[]={-,-,-,,,,,,};
int dy[]={-,,,-,,,-,,}; const ul N=;
const ul md=;
ul calc_hash(const puu &x) {return (ull(x.fi)*N%md+x.se)%md;}
template<typename T1,typename T2>
struct hmap
{
struct Node{T1 k;T2 v;int nxt;}e[N+];
int f1[md+],ne;
void ins(const T1 &x,const T2 &y)
{
ul t=calc_hash(x);
e[++ne].k=x;e[ne].v=y;e[ne].nxt=f1[t];f1[t]=ne;
}
}; hmap<puu,P> ma;
int n;
double d;
const double MINX=-1e10,MINY=-1e10;
puu gblock(const P &x)
{
return puu((x.x-MINX)/d,(x.y-MINY)/d);
}
void clr(int n)
{
for(int i=;i<=n;i++) ma.f1[calc_hash(gblock(p[i]))]=;
ma.ne=;
}
void rebuild(int n)
{
for(int i=;i<=n;i++) ma.ins(gblock(p[i]),p[i]);
}
int main()
{
int i,j,k;puu lst,now;double td;
srand(time());
scanf("%d",&n);
for(i=;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
random_shuffle(p+,p+n+);
d=dis(p[],p[]);rebuild();
for(i=;i<=n;i++)
{
if(d<1e-) {d=;break;}
lst=gblock(p[i]);td=1e18;
for(j=;j<;j++)
{
now=mp(lst.fi+dx[j],lst.se+dy[j]);
for(k=ma.f1[calc_hash(now)];k;k=ma.e[k].nxt)
if(ma.e[k].k==now)
td=min(td,dis(ma.e[k].v,p[i]));
}
if(td<d) {clr(i-);d=td;rebuild(i-);}
ma.ins(gblock(p[i]),p[i]);
}
printf("%.4f",d);
return ;
}
(相关:
http://blog.sina.com.cn/s/blog_6fa65cf90100ol2p.html,
http://blog.sina.com.cn/s/blog_aa74c5380101gv0v.html,
https://rjlipton.wordpress.com/2009/03/01/rabin-flips-a-coin/)
求两个点集间点距离最小值
开两个哈希表,每次在一个哈希表中查询,然后插入另一个哈希表即可
常数挺大,没有分治快
注意要用%f输出double
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<ctime>
#include<cmath>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef unsigned ul;
typedef pair<ul,ul> puu;
struct P
{
double x,y;bool type;
P():x(),y(){}
P(double a,double b):x(a),y(b){}
}p[];
double sqr(double x){return x*x;}
double dis(const P &a,const P &b)
{
return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
//int dx[]={-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,};
//int dy[]={-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,};
int dx[]={-,-,-,,,,,,};
int dy[]={-,,,-,,,-,,}; const ul N=;
const ul md=;
ul calc_hash(const puu &x) {return (ull(x.fi)*N%md+x.se)%md;}
template<typename T1,typename T2>
struct hmap
{
struct Node{T1 k;T2 v;int nxt;}e[N+];
int f1[md+],ne;
void ins(const T1 &x,const T2 &y)
{
ul t=calc_hash(x);
e[++ne].k=x;e[ne].v=y;e[ne].nxt=f1[t];f1[t]=ne;
}
}; hmap<puu,P> ma1,ma2;
int n;
double d;
const double MINX=-1e10,MINY=-1e10;
puu gblock(const P &x)
{
return puu((x.x-MINX)/d,(x.y-MINY)/d);
}
void clr(int n)
{
for(int i=;i<=n;i++)
if(p[i].type)
ma2.f1[calc_hash(gblock(p[i]))]=;
else
ma1.f1[calc_hash(gblock(p[i]))]=;
ma1.ne=ma2.ne=;
}
void rebuild(int n)
{
for(int i=;i<=n;i++)
if(p[i].type)
ma2.ins(gblock(p[i]),p[i]);
else
ma1.ins(gblock(p[i]),p[i]);
}
int main()
{
int i,j,k,T;puu lst,now;double td;
hmap<puu,P> *nm1,*nm2;
srand();
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=;i<=*n;i++) scanf("%lf%lf",&p[i].x,&p[i].y),p[i].type=(i<=n);
if(n==)
{
printf("%.3f\n",dis(p[],p[]));
goto xxx;
}
swap(p[n+],p[]);
random_shuffle(p+,p+*n+);
d=dis(p[],p[]);rebuild();
for(i=;i<=*n;i++)
{
if(d<1e-) {d=;break;}
nm1=p[i].type?&ma1:&ma2;nm2=p[i].type?&ma2:&ma1;
lst=gblock(p[i]);td=1e18;
for(j=;j<;j++)
{
now=mp(lst.fi+dx[j],lst.se+dy[j]);
for(k=nm1->f1[calc_hash(now)];k;k=nm1->e[k].nxt)
if(nm1->e[k].k==now)
td=min(td,dis(nm1->e[k].v,p[i]));
}
if(td<d) {clr(i-);d=td;rebuild(i-);}
nm2->ins(gblock(p[i]),p[i]);
}
printf("%.3f\n",d);
clr(*n);
xxx:;
}
return ;
}
upd:这个基于哈希表的随机增量好像不是很对?哈希表的空间开不到O(n^2)啊,冲突概率怕是会很高?(然而实测还行啊?)
(洛谷 P1429 平面最近点对(加强版) || 洛谷 P1257 || Quoit Design HDU - 1007 ) && Raid POJ - 3714的更多相关文章
- P1429 平面最近点对[加强版] 随机化
LINK:平面最近点对 加强版 有一种分治的做法 因为按照x排序分治再按y排序 可以证明每次一个只会和周边的六个点进行更新. 好像不算很难 这里给出一种随机化的做法. 前置知识是旋转坐标系 即以某个点 ...
- 洛谷 P1429 平面最近点对(加强版) (分治模板题)
题意:有\(n\)个点对,找到它们之间的最短距离. 题解:我们先对所有点对以\(x\)的大小进行排序,然后分治,每次左右二等分递归下去,当\(l+1=r\)的时候,我们计算一下距离直接返回给上一层,若 ...
- Quoit Design (HDU 1007)平面的最近点对
题目大意:给定平面上的 n 个点,求距离最近的两个点的距离的一半. n <= 10^5. 晕乎乎的度过了一上午... 总之来学习下分治吧233 分治就是把大问题拆成小问题,然后根据对小问题处 ...
- Luogu P1429 平面最近点对(加强版)(分治)
P1429 平面最近点对(加强版) 题意 题目描述 给定平面上\(n\)个点,找出其中的一对点的距离,使得在这\(n\)个点的所有点对中,该距离为所有点对中最小的. 输入输出格式 输入格式: 第一行: ...
- P1429 平面最近点对(加强版)(分治)
P1429 平面最近点对(加强版) 主要思路: 分治,将点按横坐标为第1关键字升序排列,纵坐标为第2关键字升序排列,进入左半边和右半边进行分治. 设d为左右半边的最小点对值.然后以mid这个点为中心, ...
- p1429 平面最近点对(加强版)
传送门 分析 我们可以枚举每一个点算它的最近点 估价函数应该分为3种情况计算: 大于max,小于min,位于min和max之间 代码 #include<iostream> #include ...
- 洛谷1429 平面最近点对(KDTree)
qwq(明明可以直接分治过掉的) 但是还是当作联系了 首先,对于这种点的题,很显然的套路,我们要维护一个子树\(mx[i],mn[i]\)分别表示每个维度的最大值和最小值 (这里有一个要注意的东西!就 ...
- Luogu P1429 平面最近点对 【分治】By cellur925
题目传送门 题目大意:给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的.$n$<=100000. $Algorithm$ 最朴素的$n^2$枚举肯定 ...
- 「LuoguP1429」 平面最近点对(加强版)
题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的 输入输出格式 输入格式: 第一行:n:2≤n≤200000 接下来n行:每行两个实数:x y, ...
随机推荐
- PHP Json函数不能处理中文的解决办法
PHP5.2 新增的 json 功能是非常受欢迎的,但是经过测试发现,json_encode 对中文的处理是有问题的: 不能处理GB编码,所有的GB编码都会替换成空字符: utf8编码的中文被编码成u ...
- Android终端管理器删除文件夹
终端管理器删除文件夹不能用网上提供的: rm -rf 文件夹名 而要用: rm -r 文件夹名. http://blog.csdn.net/enhancing/article/details/8490 ...
- c/c++生成预编译文件
Preprocesses C and C++ source files and writes the preprocessed output to a file. /P Remarks The f ...
- Can't locate Log/Dispatch.pm in @INC
记录一下配置mha的时候遇到的错误,使用perl模块发送邮件的时候报以下错误: # masterha_check_ssh --conf=/data/mha/app1.cnf Can't locate ...
- vi编辑器的使用(2)
1.4 光标移动 vi编辑器中的很多命令都是基于光标当前位置的,因此,如何移动光标定位到所需要的位置是一项十分重要的工作,下面进行详细介绍(如无特别说明,下面所讲的命令都是在普通模式下执行). 1. ...
- bzoj 2238 Mst——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238 一条非树边可以对一条链的树边产生影响.注意是边,所以把边下放到点上,只要跳 top 时 ...
- VS中文档大纲视图的作用
一.在vs的菜单栏中点击视图==========>其他窗口===========>文档大纲 二.文档大纲的作用是可以查看当前Form窗体的结构,如下图 三.若果感觉控件的类型太长,可以在文 ...
- Redis GEO 特性在 LBS 中的应用总结
什么是LBS LBS(Location Based Service),基于位置的服务. Redis和GEO Redis 是最热门的 nosql 数据库之一,它的最大特点就是快.所以在 LBS 这种需要 ...
- 基于微信的SDK的学习与使用——实现产品支付
声明本篇博客为作者原创,本篇是继支付宝支付之后本人又学习的第二种支付实现,本篇着重于原理与注意事项的学习. 参考 参考 微信支付的开发文档相比支付宝的比较简单,但是使用功能丝毫也不含糊,我觉得简单易 ...
- wannafly test D
题意: 给定n,m求满足: 1.a[i][j]互不相同,且有$1<=a[i][j]<=n*m$ 2.对于$a[i1][j1],a[i2][j2]$,如果有 $i1 \oplus j1 &g ...