2012-A3-0025
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
代码写得比较长,还剩了好些调试信息,懒得删了
{{{
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cassert>
#include<cstdlib>
#include<iostream>
using namespace std;
#define InCase(x) if(__builtin_expect((x),0))
typedef double real;
const real
g = 10,
inf = 1e64,
eps = 1e-8;
static real
ans;
#define sqr(x) ((x)*(x))
inline void check(real tmp){
InCase(tmp<0)
throw "At check(real): tmp < 0!";
if(tmp<ans)
ans= tmp;
}
inline real vat(real y){
// return the speed at y
const static real k = g*-2.0;
InCase(y>0){
throw "At vat(real): Sqrt a negetive real";
}
return sqrt(k*y);
}
inline real walk(real xa,real ya,real xb,real yb){
//return the time walk between (xa,yb) and (xb,yb)
const static real ka = sqrt(2.0/g);
InCase(ya>0 || yb > 0){
return inf;
throw "At walk(real, ...): y higher than 0";
}
InCase(ya>eps||yb>eps)return inf;
if(fabs(ya - yb)<eps){
if(ya<-eps)
return fabs(xa - xb)/vat(yb);
else return inf;
}
//printf("%.8lf\n",ka*hypot(xa-xb,ya-yb)/(sqrt(-ya)+sqrt(-yb)));
return ka*hypot(xa-xb,ya-yb)/(sqrt(-ya)+sqrt(-yb));
}
pair<real,real> cross(real r0,real r1,real xc,real yc){
// a circle at (0,0) radical = r0
// a circle at (xc,yc) radical = r1
// return the cross point choosing the one with small y
// when xc == 0 ,return the one with positive x
//x^2 + y ^2 =r0^2
//(x-xc)^2 + (y-yc)^2 =r1^2
//2xc*x + 2yc*y = r0^2 -r1^2+xc^2 + yc^2
static real x,y;
InCase(fabs(xc)+fabs(yc)<eps){
throw "At cross(real,...): circle has same middle";
}
if(fabs(xc)>eps){
real oc = sqr(xc)+sqr(yc), t = oc + sqr(r0)-sqr(r1);
real A = oc * 4, B = -4 * t * yc, C = sqr(t)-sqr(r0*2*xc);
y= (-B-sqrt(sqr(B)-4*A*C))/(2*A);
x=(t*0.5-y*yc)/xc;
}else{
y =(sqr(r0)+sqr(xc)+sqr(yc)-sqr(r1))/(yc*2);
x = sqrt(sqr(r0)-sqr(y));
}
return make_pair(x,y);
}
real walk2(real xd,real yd,real a,real b){
// time from (0,0) to (xd,yd) through pipe length a then lenght b.
InCase(yd>0){
return inf;
throw "At walk2(real, ...): y higher than 0";
}
InCase(fabs(xd)+fabs(yd)<eps){
assert(fabs(a-b)<eps);
return walk(0,0,0,-a)*2;
}
static pair<real,real> p;
InCase(fabs(hypot(xd,yd)-(a+b))<eps)
return walk(0,0,xd,yd);
p = cross(a,b,xd,yd);
return (p.second< -eps)?
walk(0,0,p.first,p.second)+walk(p.first,p.second,xd,yd)
: inf;
}
class FindMin{
real x,y,a,b,c;
const static real
g1 = 0.6180339887498948482045868343656381177203091798057628,
g2 = 0.3819660112501051517954131656343618822796908201942372;
real f(real ang){
static real tx,ty;
tx = x + c * cos(ang);
ty = y + c * sin(ang);
return walk2(tx,ty,a,b)+walk(tx,ty,x,y);
}
public:
FindMin(real _x,real _y,real _a,real _b ,real _c){
x = _x;y = _y;a = _a;b = _b;c = _c;
}
real Min(real l,real r){
static real ml,mr,fml,fmr;
if(l>r+eps){
return inf;
printf("%d %d %d %d %d\n",(int)(x),(int)(y),(int)(a+eps),(int)(b+eps),(int)(c+eps));
throw "at Min(real,real): bound error";
}
if(r-l>100){
return min(Min(l,(l+r)*0.5+eps),Min((l+r)*0.5-eps,r));
}
fml = f(ml = l * g1 + r * g2);
fmr = f(mr = r * g1 + l * g2);
for(size_t i=0;i<96;++i)
if(fml>fmr){
l = ml;
fml = fmr;
ml = mr;
fmr = f(mr = r *g1 + l * g2);
}else{
r = mr;
fmr = fml;
mr = ml;
fml = f(ml = l * g1 + r * g2);
}
/*
for(size_t i=0;i<200;++i){
ml = l*0.666666666666666666666666666666667 + r * 0.33333333333333333333333333333;
mr = r*0.666666666666666666666666666666667 + l * 0.33333333333333333333333333333;
if(f(ml)>f(mr))l=ml;
else r= mr;
}*/
return f((l+r)*0.5);
}
};
real walk3(real xd,real yd,real a ,real b, real c){
// time from (0,0) to (xd,yd) through pipe length a then lenght b ,length c.
static pair<real , real> p ;
static real l,r,Jl,Jr,tm;
static real ri,ro,rd;
ri = fabs(a-b);
ro = a+b;
rd = hypot(xd,yd);
InCase( ri > rd + c + eps || fabs(rd -c)> ro +eps )
return inf;
InCase(fabs(rd -(ro+c))<eps)
return walk(0,0,xd,yd);
if(xd>0)xd = -xd;//make it in 3rd Quadrant
FindMin app(xd,yd,a,b,c);
InCase(fabs(xd)+fabs(yd)<eps){
// handle (0,0)to(0,0)
l = -M_PI;
r = -acos((sqr(a)+sqr(c)-sqr(b))/(2*a*c));
return app.Min(l,r);
}else{
l = (yd<-eps)?atan2(yd,xd):-M_PI;
r = l+ M_PI;
if( ro < rd + c){
p = cross (ro,c,xd,yd);
l = max(l,atan2(p.second-yd,p.first-xd));
}
if( ri > fabs(rd - c)){
p = cross (ri,c,xd,yd);
r = min(r,atan2(p.second-yd,p.first-xd));
}
tm = atan2(yd,xd);
Jr = tm*2-l;
Jl = Jr - (r-l);
InCase(c > -yd){
r = min(r , atan2(-yd, sqrt(sqr(c)-sqr(yd))));
Jl = max(Jl , atan2(-yd, -sqrt(sqr(c)-sqr(yd)))-2*M_PI);
}
return min(app.Min(l,r),app.Min(Jl,Jr));
}
//if(l>r+eps)return inf;
//return min(FindMin(xd,yd,a,b,c).Min(0,M_PI),FindMin(xd,yd,a,b,c).Min(-M_PI,0));
}
void test(){
printf("%.12lf\n",walk(0,0,0,-5));
printf("%.12lf\n",walk(0,0,5,-5));
printf("%.12lf\n",walk(0,-5,10,-5));
printf("%.12lf\n",walk(9,-5,9,-20));
printf("%.12lf\n",walk2(5,-5,5,5));
printf("%.12lf\n",walk2(-3,-4,1,4));
}
int main(){
//test();return 0;
for(int l[3],x,y;scanf("%d%d%d%d%d",&x,&y,l,l+1,l+2)==5;
(ans<0.5*inf)?printf("%.15lf\n",ans):puts("Impossible!")){
assert(abs(x)<=1000);
assert(abs(y)<=1000);
try{
for(int i=0;i<3;++i){
InCase(l[i]<1||l[i]>1000)throw "error input";
assert(l[i]>=1 && l[i]<=1000);
}
ans = inf;
if(y>0)continue;
real dis = hypot((real)x,(real)y);
for(int i=0;i<3;++i)
if(fabs(dis - l[i])<eps)
check(walk(0,0,x,y));
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
if(i!=j){
if(l[i]+l[j]+eps>dis && fabs(l[i]-l[j])<eps+dis)
check(walk2(x,y,l[i],l[j]));
check(walk3(x,y,l[i],l[j],l[3-i-j]));
//printf("%d %d %d %d %d:%.15lf\n",x,y,l[i],l[j],l[3-i-j],walk3(x,y,l[i],l[j],l[3-i-j]));
}
}
catch(const char* error){
puts("_____________________________________");
puts(error);
puts("at case:");
printf("%d %d %d %d %d\n",x,y,l[0],l[1],l[2]);
puts("_____________________________________");
}
catch(...){
exit(-1);
}
}
}
}}}
代码写得比较长,还剩了好些调试信息,懒得删了
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cassert>
#include<cstdlib>
#include<iostream>
using namespace std;
#define InCase(x) if(__builtin_expect((x),0))
typedef double real;
const real
g = 10,
inf = 1e64,
eps = 1e-8;
static real
ans;
#define sqr(x) ((x)*(x))
inline void check(real tmp){
InCase(tmp<0)
throw "At check(real): tmp < 0!";
if(tmp<ans)
ans= tmp;
}
inline real vat(real y){
// return the speed at y
const static real k = g*-2.0;
InCase(y>0){
throw "At vat(real): Sqrt a negetive real";
}
return sqrt(k*y);
}
inline real walk(real xa,real ya,real xb,real yb){
//return the time walk between (xa,yb) and (xb,yb)
const static real ka = sqrt(2.0/g);
InCase(ya>0 || yb > 0){
return inf;
throw "At walk(real, ...): y higher than 0";
}
InCase(ya>eps||yb>eps)return inf;
if(fabs(ya - yb)<eps){
if(ya<-eps)
return fabs(xa - xb)/vat(yb);
else return inf;
}
//printf("%.8lf\n",ka*hypot(xa-xb,ya-yb)/(sqrt(-ya)+sqrt(-yb)));
return ka*hypot(xa-xb,ya-yb)/(sqrt(-ya)+sqrt(-yb));
}
pair<real,real> cross(real r0,real r1,real xc,real yc){
// a circle at (0,0) radical = r0
// a circle at (xc,yc) radical = r1
// return the cross point choosing the one with small y
// when xc == 0 ,return the one with positive x
//x^2 + y ^2 =r0^2
//(x-xc)^2 + (y-yc)^2 =r1^2
//2xc*x + 2yc*y = r0^2 -r1^2+xc^2 + yc^2
static real x,y;
InCase(fabs(xc)+fabs(yc)<eps){
throw "At cross(real,...): circle has same middle";
}
if(fabs(xc)>eps){
real oc = sqr(xc)+sqr(yc), t = oc + sqr(r0)-sqr(r1);
real A = oc * 4, B = -4 * t * yc, C = sqr(t)-sqr(r0*2*xc);
y= (-B-sqrt(sqr(B)-4*A*C))/(2*A);
x=(t*0.5-y*yc)/xc;
}else{
y =(sqr(r0)+sqr(xc)+sqr(yc)-sqr(r1))/(yc*2);
x = sqrt(sqr(r0)-sqr(y));
}
return make_pair(x,y);
}
real walk2(real xd,real yd,real a,real b){
// time from (0,0) to (xd,yd) through pipe length a then lenght b.
InCase(yd>0){
return inf;
throw "At walk2(real, ...): y higher than 0";
}
InCase(fabs(xd)+fabs(yd)<eps){
assert(fabs(a-b)<eps);
return walk(0,0,0,-a)*2;
}
static pair<real,real> p;
InCase(fabs(hypot(xd,yd)-(a+b))<eps)
return walk(0,0,xd,yd);
p = cross(a,b,xd,yd);
return (p.second< -eps)?
walk(0,0,p.first,p.second)+walk(p.first,p.second,xd,yd)
: inf;
}
class FindMin{
real x,y,a,b,c;
const static real
g1 = 0.6180339887498948482045868343656381177203091798057628,
g2 = 0.3819660112501051517954131656343618822796908201942372;
real f(real ang){
static real tx,ty;
tx = x + c * cos(ang);
ty = y + c * sin(ang);
return walk2(tx,ty,a,b)+walk(tx,ty,x,y);
}
public:
FindMin(real _x,real _y,real _a,real _b ,real _c){
x = _x;y = _y;a = _a;b = _b;c = _c;
}
real Min(real l,real r){
static real ml,mr,fml,fmr;
if(l>r+eps){
return inf;
printf("%d %d %d %d %d\n",(int)(x),(int)(y),(int)(a+eps),(int)(b+eps),(int)(c+eps));
throw "at Min(real,real): bound error";
}
if(r-l>100){
return min(Min(l,(l+r)*0.5+eps),Min((l+r)*0.5-eps,r));
}
fml = f(ml = l * g1 + r * g2);
fmr = f(mr = r * g1 + l * g2);
for(size_t i=0;i<96;++i)
if(fml>fmr){
l = ml;
fml = fmr;
ml = mr;
fmr = f(mr = r *g1 + l * g2);
}else{
r = mr;
fmr = fml;
mr = ml;
fml = f(ml = l * g1 + r * g2);
}
/*
for(size_t i=0;i<200;++i){
ml = l*0.666666666666666666666666666666667 + r * 0.33333333333333333333333333333;
mr = r*0.666666666666666666666666666666667 + l * 0.33333333333333333333333333333;
if(f(ml)>f(mr))l=ml;
else r= mr;
}*/
return f((l+r)*0.5);
}
};
real walk3(real xd,real yd,real a ,real b, real c){
// time from (0,0) to (xd,yd) through pipe length a then lenght b ,length c.
static pair<real , real> p ;
static real l,r,Jl,Jr,tm;
static real ri,ro,rd;
ri = fabs(a-b);
ro = a+b;
rd = hypot(xd,yd);
InCase( ri > rd + c + eps || fabs(rd -c)> ro +eps )
return inf;
InCase(fabs(rd -(ro+c))<eps)
return walk(0,0,xd,yd);
if(xd>0)xd = -xd;//make it in 3rd Quadrant
FindMin app(xd,yd,a,b,c);
InCase(fabs(xd)+fabs(yd)<eps){
// handle (0,0)to(0,0)
l = -M_PI;
r = -acos((sqr(a)+sqr(c)-sqr(b))/(2*a*c));
return app.Min(l,r);
}else{
l = (yd<-eps)?atan2(yd,xd):-M_PI;
r = l+ M_PI;
if( ro < rd + c){
p = cross (ro,c,xd,yd);
l = max(l,atan2(p.second-yd,p.first-xd));
}
if( ri > fabs(rd - c)){
p = cross (ri,c,xd,yd);
r = min(r,atan2(p.second-yd,p.first-xd));
}
tm = atan2(yd,xd);
Jr = tm*2-l;
Jl = Jr - (r-l);
InCase(c > -yd){
r = min(r , atan2(-yd, sqrt(sqr(c)-sqr(yd))));
Jl = max(Jl , atan2(-yd, -sqrt(sqr(c)-sqr(yd)))-2*M_PI);
}
return min(app.Min(l,r),app.Min(Jl,Jr));
}
//if(l>r+eps)return inf;
//return min(FindMin(xd,yd,a,b,c).Min(0,M_PI),FindMin(xd,yd,a,b,c).Min(-M_PI,0));
}
void test(){
printf("%.12lf\n",walk(0,0,0,-5));
printf("%.12lf\n",walk(0,0,5,-5));
printf("%.12lf\n",walk(0,-5,10,-5));
printf("%.12lf\n",walk(9,-5,9,-20));
printf("%.12lf\n",walk2(5,-5,5,5));
printf("%.12lf\n",walk2(-3,-4,1,4));
}
int main(){
//test();return 0;
for(int l[3],x,y;scanf("%d%d%d%d%d",&x,&y,l,l+1,l+2)==5;
(ans<0.5*inf)?printf("%.15lf\n",ans):puts("Impossible!")){
assert(abs(x)<=1000);
assert(abs(y)<=1000);
try{
for(int i=0;i<3;++i){
InCase(l[i]<1||l[i]>1000)throw "error input";
assert(l[i]>=1 && l[i]<=1000);
}
ans = inf;
if(y>0)continue;
real dis = hypot((real)x,(real)y);
for(int i=0;i<3;++i)
if(fabs(dis - l[i])<eps)
check(walk(0,0,x,y));
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
if(i!=j){
if(l[i]+l[j]+eps>dis && fabs(l[i]-l[j])<eps+dis)
check(walk2(x,y,l[i],l[j]));
check(walk3(x,y,l[i],l[j],l[3-i-j]));
//printf("%d %d %d %d %d:%.15lf\n",x,y,l[i],l[j],l[3-i-j],walk3(x,y,l[i],l[j],l[3-i-j]));
}
}
catch(const char* error){
puts("_____________________________________");
puts(error);
puts("at case:");
printf("%d %d %d %d %d\n",x,y,l[0],l[1],l[2]);
puts("_____________________________________");
}
catch(...){
exit(-1);
}
}
}