POJ 3608 旋转卡壳

题意:

求两个凸包的最近距离。

 

题解:

原来旋转卡壳这么暴力。。我以前一直以为是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了一下午。。

 

 

posted @ 2013-02-25 21:20  proverbs  阅读(581)  评论(5编辑  收藏  举报