这个讲的好:
分治法
先空着
看一下这个第三个方法(随机增量哈希,O(n))
1.千万不要用unordered_map/hash_map!T飞是肯定的;要手写哈希表,所以码量就很大;手写哈希表方法记一下
2.事实上以d为边长画格子,每次遍历相邻的9个格子,常数要比以d/2边长画格子,每次遍历相邻25个格子要好(当然此时每个格子里面不一定只有一个数了);不知道为什么
3.注意,用此方法时,如果距离已经为0了,那么就马上跳出循环(不然可能由于除以0或很接近0的数产生非常大的格子编号,产生不好的事情)
4.常数似乎较大,比一些分治法要慢
别人的代码!跑的飞快(交洛谷)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 #include <string.h> 5 #include <math.h> 6 #define MAXN 201000 7 #define DUBF 999999999.9 8 #define INF 201007 9 struct NODE 10 { 11 int to; 12 int next; 13 }; 14 struct NODE1 15 { 16 double x, y; 17 }; 18 int direction[9][2] = {0, 0, -1, -1, -1, 0, -1, 1, 0, 1, 1, 1, 1, 0, 1, -1, 0, -1}; 19 NODE1 point[MAXN]; 20 NODE edges[MAXN]; 21 int ad; 22 int map[INF]; 23 int HASH(int x, int y) 24 { 25 return ((x * MAXN + y) % INF + INF) % INF; 26 } 27 double len(int i, int j) 28 { 29 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)); 30 } 31 void Into_Hash(int i, double r) 32 { 33 edges[ad].to = i; 34 edges[ad].next = map[HASH( (int)(point[i].x/r), (int)(point[i].y/r) )]; 35 map[HASH( (int)(point[i].x/r), (int)(point[i].y/r) )] = ad ++; 36 } 37 void Renew_Hash(int n, double r) 38 { 39 ad = 0; 40 memset(map, -1, sizeof(map)); 41 for(int i = 0; i <= n; i ++) 42 Into_Hash(i, r); 43 } 44 double Get_len_around(int p, double r) 45 { 46 int x = (int) (point[p].x / r), y = (int) (point[p].y / r), i, j; 47 double s = DUBF; 48 for(int k = 0; k < 9; k ++) 49 { 50 i = x + direction[k][0], j = y + direction[k][1]; 51 for(int q = map[HASH(i, j)]; ~q; q = edges[q].next) 52 s = s < len(edges[q].to, p) ? s : len(edges[q].to, p); 53 } 54 return s; 55 } 56 double Get_R(int n) 57 { 58 double r = len(0, 1), s; 59 int i; 60 if(r - 0 < 1e-6 || n < 2) 61 return 0; 62 Renew_Hash(1, r); 63 for(i = 2; i < n; i ++) 64 if((s = Get_len_around(i, r)) < r) 65 { 66 r = s; 67 if(r - 0 < 1e-6) 68 return 0; 69 Renew_Hash(i, r); 70 } 71 else 72 Into_Hash(i, r); 73 return r; 74 } 75 void swap(int i, int j) 76 { 77 NODE1 t = point[i]; 78 point[i] = point[j]; 79 point[j] = t; 80 } 81 int main() 82 { 83 int n, i; 84 while(scanf("%d", &n)==1) 85 { 86 for(i = 0; i < n; i ++) 87 scanf("%lf %lf", &point[i].x, &point[i].y); 88 srand((unsigned)time(NULL)); 89 for(i = 0; i < n; i ++) 90 swap(i, rand() % n); 91 printf("%.4lf ", Get_R(n)); 92 } 93 return 0; 94 95 }
自己的代码(跑的慢不少,找不出来原因)(交洛谷)
1 #pragma GCC optimize("Ofast") 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 #include<ctime> 7 using namespace std; 8 #define fi first 9 #define se second 10 #define mp make_pair 11 #define pb push_back 12 typedef long long ll; 13 typedef unsigned long long ull; 14 typedef pair<int,int> pii; 15 typedef unsigned ul; 16 typedef pair<ul,ul> puu; 17 struct P 18 { 19 double x,y; 20 P():x(0),y(0){} 21 P(double a,double b):x(a),y(b){} 22 }p[200100]; 23 double sqr(double x){return x*x;} 24 double dis(const P &a,const P &b) 25 { 26 return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); 27 } 28 //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,}; 29 //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,}; 30 int dx[]={-1,-1,-1,0,0,0,1,1,1}; 31 int dy[]={-1,0,1,-1,0,1,-1,0,1}; 32 33 const ul N=200000; 34 const ul md=999983; 35 ul calc_hash(const puu &x) {return (ull(x.fi)*N%md+x.se)%md;} 36 template<typename T1,typename T2> 37 struct hmap 38 { 39 struct Node{T1 k;T2 v;int nxt;}e[N+100]; 40 int f1[md+1],ne; 41 void ins(const T1 &x,const T2 &y) 42 { 43 ul t=calc_hash(x); 44 e[++ne].k=x;e[ne].v=y;e[ne].nxt=f1[t];f1[t]=ne; 45 } 46 }; 47 48 hmap<puu,P> ma; 49 int n; 50 double d; 51 const double MINX=-1e10,MINY=-1e10; 52 puu gblock(const P &x) 53 { 54 return puu((x.x-MINX)/d,(x.y-MINY)/d); 55 } 56 void clr(int n) 57 { 58 for(int i=1;i<=n;i++) ma.f1[calc_hash(gblock(p[i]))]=0; 59 ma.ne=0; 60 } 61 void rebuild(int n) 62 { 63 for(int i=1;i<=n;i++) ma.ins(gblock(p[i]),p[i]); 64 } 65 int main() 66 { 67 int i,j,k;puu lst,now;double td; 68 srand(time(0)); 69 scanf("%d",&n); 70 for(i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); 71 random_shuffle(p+1,p+n+1); 72 d=dis(p[1],p[2]);rebuild(2); 73 for(i=3;i<=n;i++) 74 { 75 if(d<1e-6) {d=0;break;} 76 lst=gblock(p[i]);td=1e18; 77 for(j=0;j<9;j++) 78 { 79 now=mp(lst.fi+dx[j],lst.se+dy[j]); 80 for(k=ma.f1[calc_hash(now)];k;k=ma.e[k].nxt) 81 if(ma.e[k].k==now) 82 td=min(td,dis(ma.e[k].v,p[i])); 83 } 84 if(td<d) {clr(i-1);d=td;rebuild(i-1);} 85 ma.ins(gblock(p[i]),p[i]); 86 } 87 printf("%.4f",d); 88 return 0; 89 }
(相关:
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
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<ctime> 6 #include<cmath> 7 using namespace std; 8 #define fi first 9 #define se second 10 #define mp make_pair 11 #define pb push_back 12 typedef long long ll; 13 typedef unsigned long long ull; 14 typedef pair<int,int> pii; 15 typedef unsigned ul; 16 typedef pair<ul,ul> puu; 17 struct P 18 { 19 double x,y;bool type; 20 P():x(0),y(0){} 21 P(double a,double b):x(a),y(b){} 22 }p[200100]; 23 double sqr(double x){return x*x;} 24 double dis(const P &a,const P &b) 25 { 26 return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); 27 } 28 //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,}; 29 //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,}; 30 int dx[]={-1,-1,-1,0,0,0,1,1,1}; 31 int dy[]={-1,0,1,-1,0,1,-1,0,1}; 32 33 const ul N=200000; 34 const ul md=999983; 35 ul calc_hash(const puu &x) {return (ull(x.fi)*N%md+x.se)%md;} 36 template<typename T1,typename T2> 37 struct hmap 38 { 39 struct Node{T1 k;T2 v;int nxt;}e[N+100]; 40 int f1[md+1],ne; 41 void ins(const T1 &x,const T2 &y) 42 { 43 ul t=calc_hash(x); 44 e[++ne].k=x;e[ne].v=y;e[ne].nxt=f1[t];f1[t]=ne; 45 } 46 }; 47 48 hmap<puu,P> ma1,ma2; 49 int n; 50 double d; 51 const double MINX=-1e10,MINY=-1e10; 52 puu gblock(const P &x) 53 { 54 return puu((x.x-MINX)/d,(x.y-MINY)/d); 55 } 56 void clr(int n) 57 { 58 for(int i=1;i<=n;i++) 59 if(p[i].type) 60 ma2.f1[calc_hash(gblock(p[i]))]=0; 61 else 62 ma1.f1[calc_hash(gblock(p[i]))]=0; 63 ma1.ne=ma2.ne=0; 64 } 65 void rebuild(int n) 66 { 67 for(int i=1;i<=n;i++) 68 if(p[i].type) 69 ma2.ins(gblock(p[i]),p[i]); 70 else 71 ma1.ins(gblock(p[i]),p[i]); 72 } 73 int main() 74 { 75 int i,j,k,T;puu lst,now;double td; 76 hmap<puu,P> *nm1,*nm2; 77 srand(616); 78 scanf("%d",&T); 79 while(T--) 80 { 81 scanf("%d",&n); 82 for(i=1;i<=2*n;i++) scanf("%lf%lf",&p[i].x,&p[i].y),p[i].type=(i<=n); 83 if(n==1) 84 { 85 printf("%.3f ",dis(p[1],p[2])); 86 goto xxx; 87 } 88 swap(p[n+1],p[2]); 89 random_shuffle(p+3,p+2*n+1); 90 d=dis(p[1],p[2]);rebuild(2); 91 for(i=3;i<=2*n;i++) 92 { 93 if(d<1e-6) {d=0;break;} 94 nm1=p[i].type?&ma1:&ma2;nm2=p[i].type?&ma2:&ma1; 95 lst=gblock(p[i]);td=1e18; 96 for(j=0;j<9;j++) 97 { 98 now=mp(lst.fi+dx[j],lst.se+dy[j]); 99 for(k=nm1->f1[calc_hash(now)];k;k=nm1->e[k].nxt) 100 if(nm1->e[k].k==now) 101 td=min(td,dis(nm1->e[k].v,p[i])); 102 } 103 if(td<d) {clr(i-1);d=td;rebuild(i-1);} 104 nm2->ins(gblock(p[i]),p[i]); 105 } 106 printf("%.3f ",d); 107 clr(2*n); 108 xxx:; 109 } 110 return 0; 111 }
upd:这个基于哈希表的随机增量好像不是很对?哈希表的空间开不到O(n^2)啊,冲突概率怕是会很高?(然而实测还行啊?)