(洛谷 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, ...
随机推荐
- bzoj4485: [Jsoi2015]圈地
思维僵化选手在线被虐 其实应该是不难的,题目明显分成两个集合,要求是不同集合的点不能联通 先假设全选了,然后二分图最小割,相邻两个点直接连墙的费用就可以了 #include<cstdio> ...
- HDU2829 Lawrence —— 斜率优化DP
题目链接:https://vjudge.net/problem/HDU-2829 Lawrence Time Limit: 2000/1000 MS (Java/Others) Memory L ...
- 【C/C++】产生随机数
#include<iostream> #include<Ctime> #include<Cstdlib> using namespace std; //产生n个st ...
- 并不对劲的bzoj3677:p3647:[APIO2014]连珠线
题目大意 有一种生成\(n\)个点的树的方法为: 一开始有一个点,\(n-1\)次操作,每次可以有两种操作:1.选一个点,用一条红边将它与新点连接:2.将新点放在一条红边上,新点与这条红边两端点直接的 ...
- Swift类型转换
关于「类型转换」(Type Casting),<The Swift Programming Language>描述如下: Type casting is a way to check th ...
- C++之虚函数与虚继承详解
准备工作 1.VS2012使用命令行选项查看对象的内存布局 微软的Visual Studio提供给用户显示C++对象在内存中的布局的选项:/d1reportSingleClassLayout.使用方法 ...
- 使用基于Caffe的MobileNet分类踩坑备忘录
首先要帮Caffe甩个锅:Caffe对图像处理进行了很高明的封装,以protobuffer形式组织的搭积木式的网络构建也很灵活方便,这里的坑都是自己腿不好,走路不稳崴进去的. 1. Caffe的一个i ...
- 关于数组array的一些误区
$arr1 = array(1,2,3,4); $arr2 = array(5,6,7,8,9,10); var_dump ( $arr1 + $arr2); //输出数组形式的(1,2,3,4 ...
- char的定义在iOS和Android下是不同的
char is different in iOS and Android!跨平台开发时很容易忽略的非常坑爹的一个区别. 我的需求是实现一个算法,这个算法在iOS和Android下需要保持一致的结果,很 ...
- CF-799A
A. Carrot Cakes time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...