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了一下午。。

 

 

你可能感兴趣的:(360)