poj3608Bridge Across Islands(凸包间最小距离)
以下所有文章均转载( http://blog.csdn.net/acmaker/article/details/3176910) 转载请注明出处!
考虑如下的算法, 算法的输入是两个分别有 m 和 n 个顺时针给定顶点的凸多边形 P 和 Q。
- 计算 P 上 y 坐标值最小的顶点(称为 yminP ) 和 Q 上 y 坐标值最大的顶点(称为 ymaxQ)。
- 为多边形在 yminP 和 ymaxQ 处构造两条切线 LP 和 LQ 使得他们对应的多边形位于他们的右侧。 此时 LP 和 LQ 拥有不同的方向, 并且 yminP 和 ymaxQ 成为了多边形间的一个对踵点对。
- 计算距离(yminP,ymaxQ) 并且将其维护为当前最小值。
- 顺时针同时旋转平行线直到其中一个与其所在的多边形的边重合。
- 如果只有一条线与边重合, 那么只需要计算“顶点-边”对踵点对和“顶点-顶点”对踵点对距离。 都将他们与当前最小值比较, 如果小于当前最小值则进行替换更新。 如果两条切线都与边重合, 那么情况就更加复杂了。 如果边“交叠”, 也就是可以构造一条与两条边都相交的公垂线(但不是在顶点处相交), 那么就计算“边-边”距离。 否则计算三个新的“顶点-顶点”对踵点对距离。 所有的这些距离都与当前最小值进行比较, 若小于当前最小值则更新替换。
- 重复执行步骤4和步骤5, 直到新的点对为(yminP,ymaxQ)。
- 输出最大距离。
以上是转载。。以下是原创。。
上面是按顺时针存的凸包也是按顺时针旋转的平行线,网上很多是逆时针的凸包却写着顺时针的做法,但代码依旧A了,,不是很理解。。
逆时针 改反一点 依旧A。。。
感觉自己 的是对的吧。。。
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 using namespace std; 11 #define N 10010 12 #define LL long long 13 #define INF 0xfffffff 14 const double eps = 1e-9; 15 const double pi = acos(-1.0); 16 const double inf = ~0u>>2; 17 struct Point 18 { 19 double x,y; 20 Point(double x=0,double y=0):x(x),y(y) {} //构造函数 方便代码编写 21 }p[N],q[N]; 22 typedef Point pointt; 23 pointt operator + (Point a,Point b) 24 { 25 return Point(a.x+b.x,a.y+b.y); 26 } 27 pointt operator - (Point a,Point b) 28 { 29 return Point(a.x-b.x,a.y-b.y); 30 } 31 int dcmp(double x) 32 { 33 if(fabs(x)<eps) return 0; 34 else return x<0?-1:1; 35 } 36 bool operator == (const Point &a,const Point &b) 37 { 38 return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; 39 } 40 double dot(Point a,Point b) 41 { 42 return a.x*b.x+a.y*b.y; 43 } 44 double dis(Point a) 45 { 46 return sqrt(dot(a,a)); 47 } 48 double cross(Point a,Point b) 49 { 50 return a.x*b.y-a.y*b.x; 51 } 52 void anticlock(Point p[],int n) 53 { 54 for(int i = 0 ; i < n-2 ; i++) 55 { 56 double k = cross(p[i+1]-p[0],p[i+2]-p[0]); 57 if(dcmp(k)>0) return ; 58 else if(dcmp(k)<0) 59 { 60 reverse(p,p+n); 61 return ; 62 } 63 } 64 } 65 double distoline(Point a,Point b,Point c) 66 { 67 if(dcmp(dis(a-b))==0) return dis(a-c); 68 if(dcmp(dot(a-b,a-c))<0) return dis(a-c); 69 if(dcmp(dot(b-a,b-c))<0) return dis(b-c); 70 return fabs(cross(a-b,a-c))/dis(a-b); 71 } 72 double dist(Point a,Point b,Point c,Point d) 73 { 74 double ans = distoline(a,b,c); 75 ans = min(ans,distoline(a,b,d)); 76 ans = min(ans,distoline(c,d,a)); 77 ans = min(ans,distoline(c,d,b)); 78 return ans; 79 } 80 double mul(Point a,Point b,Point c) 81 { 82 return cross(b-a,c-a); 83 } 84 double solve(Point p[],int n,Point q[],int m) 85 { 86 int i; 87 int miny = 0,maxy = 0; 88 for(i = 0;i < n; i++) 89 { 90 if(p[i].y<p[miny].y) 91 miny = i; 92 } 93 for(i =0 ; i< m ; i++) 94 if(q[i].y>q[maxy].y) maxy = i; 95 double ans = dis(p[miny]-q[maxy]); 96 for(i = 0 ;i < n; i++) 97 { 98 double tmp; 99 while(tmp = mul(p[miny],p[miny+1],q[maxy+1])-mul(p[miny],p[miny+1],q[maxy])>eps) 100 maxy = (maxy+1)%m; 101 if(dcmp(tmp)>0) ans = min(ans,distoline(p[miny],p[miny+1],q[maxy]));//这里如果写成<0 画图可以看出是顺时针的做法 就算不加这句直接算下面的也能A。。 102 else 103 ans = min(ans,dist(p[miny],p[miny+1],q[maxy],q[maxy+1]));//边-边 104 miny = (miny+1)%n; 105 } 106 return ans; 107 } 108 int main() 109 { 110 int i,n,m; 111 while(scanf("%d%d",&n,&m)&&n&&m) 112 { 113 for(i = 0 ; i < n ; i++) 114 scanf("%lf%lf",&p[i].x,&p[i].y); 115 for(i = 0 ;i < m ;i++) 116 scanf("%lf%lf",&q[i].x,&q[i].y); 117 anticlock(p,n); 118 anticlock(q,m); 119 p[n] = p[0]; 120 121 q[m] = q[0]; 122 double ans = min(solve(p,n,q,m),solve(q,m,p,n)); 123 124 printf("%.5f\n",ans); 125 } 126 return 0; 127 }