题意:
求两个凸包的最近距离。
题解:
原来旋转卡壳这么暴力。。我以前一直以为是O(n)的。。。
画画图,用叉积判断下旋转角度就行了~
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <cmath> 7 8 #define N 22222 9 #define PI 3.14159265358979 10 #define EPS 1e-7 11 12 using namespace std; 13 14 struct PO 15 { 16 double x,y; 17 }p1[N],p2[N],o; 18 19 int n,m,top1,top2,stk1[N],stk2[N]; 20 21 inline int doublecmp(double x) 22 { 23 if(x>EPS) return 1; 24 else if(x<-EPS) return -1; 25 return 0; 26 } 27 28 inline bool cmp(const PO &a,const PO &b) 29 { 30 if(doublecmp(a.x-b.x)==0) return a.y<b.y; 31 return a.x<b.x; 32 } 33 34 inline void read() 35 { 36 for(int i=1;i<=n;i++) scanf("%lf%lf",&p1[i].x,&p1[i].y); 37 for(int i=1;i<=m;i++) scanf("%lf%lf",&p2[i].x,&p2[i].y); 38 } 39 40 inline PO operator +(PO a,PO b) 41 { 42 PO c; 43 c.x=a.x+b.x; 44 c.y=a.y+b.y; 45 return c; 46 } 47 48 inline PO operator -(PO a,PO b) 49 { 50 PO c; 51 c.x=a.x-b.x; 52 c.y=a.y-b.y; 53 return c; 54 } 55 56 inline double dot(PO &a,PO &b,PO &c) 57 { 58 return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y); 59 } 60 61 inline double cross(PO &a,PO &b,PO &c) 62 { 63 return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); 64 } 65 66 inline double getlen(PO &a)//向量的模 67 { 68 return sqrt(a.x*a.x+a.y*a.y); 69 } 70 71 inline PO getty(PO b,PO a)//投影向量 72 { 73 PO res=a; 74 double k=dot(o,a,b)/(getlen(a)*getlen(a)); 75 res.x*=k; res.y*=k; 76 return res; 77 } 78 79 inline double getangle(PO &a,PO &b,PO&c,PO &d) 80 { 81 PO t=c+(a-d); 82 return cross(a,b,t); 83 } 84 85 inline PO rotate(PO a,double hd) 86 { 87 PO c; 88 c.x=a.x*cos(hd)-a.y*sin(hd); 89 c.y=a.x*sin(hd)+a.y*cos(hd); 90 return c; 91 } 92 93 inline double getdis(PO &a,PO &b) 94 { 95 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 96 } 97 98 inline double getdis_ps(PO &a,PO &b,PO &c) 99 { 100 PO t=c-b; 101 t=rotate(t,-PI*0.5); 102 PO s=c-a;; 103 PO ty=getty(s,t); 104 s=a+ty; 105 if(doublecmp(dot(s,b,c))<=0) return getlen(ty); 106 else return min(getdis(a,b),getdis(a,c)); 107 } 108 109 inline void graham(PO *p,int *stk,int &top,int gs) 110 { 111 sort(p+1,p+1+gs,cmp); 112 top=-1; 113 stk[++top]=1; stk[++top]=2; 114 for(int i=3;i<=gs;i++) 115 { 116 while(top>=1&&doublecmp(cross(p[stk[top-1]],p[stk[top]],p[i]))<=0) top--; 117 stk[++top]=i; 118 } 119 int tmp=top; 120 for(int i=gs-1;i>=1;i--) 121 { 122 while(top>=tmp+1&&doublecmp(cross(p[stk[top-1]],p[stk[top]],p[i]))<=0) top--; 123 stk[++top]=i; 124 } 125 } 126 127 inline double rotating_calipers() 128 { 129 int s1=0,s2=0; 130 for(int i=1;i<top1;i++) 131 if(doublecmp(p1[stk1[i]].y-p1[stk1[s1]].y)<0||(doublecmp(p1[stk1[i]].y-p1[stk1[s1]].y)==0)&&doublecmp(p1[stk1[i]].x-p1[stk1[s1]].x)<0) s1=i; 132 for(int i=1;i<top2;i++) 133 if(doublecmp(p2[stk2[i]].y-p2[stk2[s2]].y)>0||(doublecmp(p2[stk2[i]].y-p2[stk2[s2]].y)==0)&&doublecmp(p2[stk2[i]].x-p2[stk2[s2]].x)>0) s2=i; 134 int t1=s1,t2=s2; 135 double ans=getdis(p1[stk1[s1]],p2[stk2[s2]]); 136 do 137 { 138 double af=getangle(p1[stk1[s1]],p1[stk1[(s1+1)%top1]],p2[stk2[s2]],p2[stk2[(s2+1)%top2]]); 139 if(doublecmp(af)==0)//卡壳到两条边 140 { 141 ans=min(ans,getdis_ps(p1[stk1[s1]],p2[stk2[s2]],p2[stk2[(s2+1)%top2]])); 142 ans=min(ans,getdis_ps(p1[stk1[(s1+1)%top1]],p2[stk2[s2]],p2[stk2[(s2+1)%top2]])); 143 ans=min(ans,getdis_ps(p2[stk2[s2]],p1[stk1[s1]],p1[stk1[(s1+1)%top1]])); 144 ans=min(ans,getdis_ps(p2[stk2[(s2+1)%top2]],p1[stk1[s1]],p1[stk1[(s1+1)%top1]])); 145 s1=(s1+1)%top1; s2=(s2+1)%top2; 146 } 147 else if(doublecmp(af)>0)//卡壳到第一个的边,第二个的点 148 { 149 ans=min(ans,getdis_ps(p2[stk2[s2]],p1[stk1[s1]],p1[stk1[(s1+1)%top1]])); 150 s1=(s1+1)%top1; 151 } 152 else//卡壳到第二个的边,第一个的点 153 { 154 ans=min(ans,getdis_ps(p1[stk1[s1]],p2[stk2[s2]],p2[stk2[(s2+1)%top2]])); 155 s2=(s2+1)%top2; 156 } 157 }while(t1!=s1||t2!=s2); 158 return ans; 159 } 160 161 inline void go() 162 { 163 graham(p1,stk1,top1,n); 164 graham(p2,stk2,top2,m); 165 printf("%.5lf\n",rotating_calipers()); 166 } 167 168 int main() 169 { 170 while(scanf("%d%d",&n,&m),n) read(),go(); 171 return 0; 172 }
这题太坑了,凸包写错了都能ac。。
害得我下一道题直接粘的这个凸包,wa了一下午。。