hdu 4454 Stealing a Cake(计算几何:最短距离、枚举/三分)
题意:已知起点、圆、矩形,要求计算从起点开始,经过圆(和圆上任一点接触即可),到达矩形的路径的最短距离。(可以穿过园)。
分析:没什么好的方法,凭感觉圆上的每个点对应最短距离,应该是一个凸函数,用三分来解。不过应该是分成两部分,用两次三分来解。具体原因不明,通过实验只能得出三分必须是针对一个凸函数,很明显,从0~2*pi不是一个凸函数,但同理,0~pi,pi~2*pi也不一定是个凸函数。个人认为,网络上流传的[0,pi][pi,2*pi]这种分法,并不存在合理性。继续思考= =
另外,直接暴力枚举也是能过的。
错误:分析圆上的点与矩形的位置关系写挫了,虽然现在还是研究不明白到底出了什么问题,应该是边界吧。
1 double rec(double x,double y) 2 { 3 check(); 4 if(x-xi<eps&&y-yj>eps) 5 return len(x,y,xi,yj); 6 else if(x-xi<eps&&y-yi<eps) 7 return len(x,y,xi,yi); 8 else if(x-xj>eps&&y-yj>eps) 9 return len(x,y,xj,yj); 10 else if(x-xj>eps&&y-yi<eps) 11 return len(x,y,xj,yj); 12 13 if(x-xi>eps&&x-xj<eps) 14 if(y-yj>eps) 15 return fabs(y-yj); 16 else if(y-yi<eps) 17 return fabs(yi-y); 18 else if(y-yi>eps&&y-yj<eps) 19 if(x-xi<eps) 20 return fabs(xi-x); 21 else if(x-xj>eps) 22 return fabs(x-xj); 23 }
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 using namespace std; 7 8 const double pi=acos(-1.0); 9 const double eps=1e-10; 10 11 double sx,sy; 12 double rx,ry,r; 13 double xi,yi,xj,yj; 14 15 double degree() 16 { 17 return atan((ry-sy)/(rx-sx)); 18 } 19 20 double len(double x,double y,double a,double b) 21 { 22 return sqrt((x-a)*(x-a)+(y-b)*(y-b)); 23 } 24 25 void change(double& x,double &y) 26 { 27 double p; 28 p=x; 29 x=y; 30 y=p; 31 } 32 33 void check() 34 { 35 if(xi>xj) 36 change(xi,xj); 37 if(yi>yj) 38 change(yi,yj); 39 } 40 41 double rec(double x,double y) 42 { 43 double lenx=0,leny=0; 44 check(); 45 if(x<xi) 46 lenx=xi-x; 47 else if(x>xj) 48 lenx=x-xj; 49 if(y<yi) 50 leny=yi-y; 51 else if(y>yj) 52 leny=y-yj; 53 return sqrt(lenx*lenx+leny*leny); 54 } 55 56 double f(double m) 57 { 58 double dx=rx+r*cos(m); 59 double dy=ry+r*sin(m); 60 61 double len1=len(dx,dy,sx,sy); 62 double len2=rec(dx,dy); 63 64 return len1+len2; 65 } 66 67 int main() 68 { 69 int n; 70 while(~scanf("%lf%lf",&sx,&sy)) 71 { 72 if(fabs(sx)<eps&&fabs(sy)<eps) 73 return 0; 74 scanf("%lf%lf%lf",&rx,&ry,&r); 75 scanf("%lf%lf%lf%lf",&xi,&yi,&xj,&yj); 76 77 double l=degree(),r=l+pi; 78 while(fabs(r-l)>eps) 79 { 80 double m1=l+(r-l)/3; 81 double m2=r-(r-l)/3; 82 if(f(m1)<f(m2)) 83 r=m2; 84 else 85 l=m1; 86 } 87 double l1=l; 88 l=degree()+pi;r=l+pi; 89 while(fabs(r-l)>eps) 90 { 91 double m1=l+(r-l)/3; 92 double m2=r-(r-l)/3; 93 if(f(m1)<f(m2)) 94 r=m2; 95 else 96 l=m1; 97 } 98 double l2=l; 99 printf("%.2f\n",min(f(l1),f(l2))); 100 } 101 return 0; 102 }
暴力枚举,奇葩的精度。不过相比较而言,这个算法根据有可信度。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 using namespace std; 7 8 const double INF=1e10; 9 const double pi=acos(-1.0); 10 const double eps=1e-10; 11 12 double sx,sy; 13 double rx,ry,r; 14 double xi,yi,xj,yj; 15 16 double len(double x,double y,double a,double b) 17 { 18 return sqrt((x-a)*(x-a)+(y-b)*(y-b)); 19 } 20 21 void change(double& x,double &y) 22 { 23 double p; 24 p=x; 25 x=y; 26 y=p; 27 } 28 29 void check() 30 { 31 if(xi>xj) 32 change(xi,xj); 33 if(yi>yj) 34 change(yi,yj); 35 } 36 37 double rec(double x,double y) 38 { 39 double lenx=0,leny=0; 40 check(); 41 if(x<xi) 42 lenx=xi-x; 43 else if(x>xj) 44 lenx=x-xj; 45 if(y<yi) 46 leny=yi-y; 47 else if(y>yj) 48 leny=y-yj; 49 return sqrt(lenx*lenx+leny*leny); 50 } 51 52 double f(double m) 53 { 54 double dx=rx+r*cos(m); 55 double dy=ry+r*sin(m); 56 57 double len1=len(dx,dy,sx,sy); 58 double len2=rec(dx,dy); 59 60 return len1+len2; 61 } 62 63 int main() 64 { 65 int n; 66 while(~scanf("%lf%lf",&sx,&sy)) 67 { 68 if(fabs(sx)<eps&&fabs(sy)<eps) 69 return 0; 70 scanf("%lf%lf%lf",&rx,&ry,&r); 71 scanf("%lf%lf%lf%lf",&xi,&yi,&xj,&yj); 72 73 double m=INF; 74 for(double i=0;i<=360;i+=0.01) 75 { 76 m=min(m,f(i/180*pi)); 77 } 78 printf("%.2f\n",m); 79 } 80 return 0; 81 }