HDU 5572An Easy Physics Problem
题意:
光滑平面,一个刚性小球,一个固定的刚性圆柱体
给定圆柱体圆心坐标,半径
小球起点坐标,起始运动方向(向量)
终点坐标
问能否到达终点,小球运动中如果碰到圆柱体会反射(基本物理知识)
思路:
根据高中平面几何知识很快找到判断方法,但是向量的代码实现有一些麻烦,浪费时间,使用向量模板会方便许多
#include<cstdio>
#include<cmath>
struct node{
double dis(node);//两点距离
//向量操作
node add(node);//加
double mul(node);//乘
node mul(double);//倍
double abs();//模长
node unt();//单位化
node neg();//取反
double agl(node);//夹角,度数
bool eql(node);//向量相等
int pal(node);//向量平行
double x,y;
};
double node::dis(node a){
return sqrt(pow(x-a.x,2)+pow(y-a.y,2));
}
node node::add(node a){
return {x+a.x,y+a.y};
}
double node::mul(node a){
return x*a.x+y*a.y;
}
node node::mul(double a){
return {x*a,y*a};
}
node node::neg(){
return {-x,-y};
}
double node::abs(){
return sqrt(x*x+y*y);
}
node node::unt(){
double d=this->abs();
return {x/d,y/d};
}
double node::agl(node a){
return acos((x*a.x+y*a.y)/(this->abs()*a.abs()));
}
bool node::eql(node a){
if(fabs(x-a.x)<1e-6&&fabs(y-a.y)<1e-6)return 1;
return 0;
}
int node::pal(node a){
node u1=this->unt();//判断单位向量
node u2=a.unt();
if(u1.eql(u2))return 1;//方向相同
if(u1.eql(u2.neg()))return -1;//方向相反
return 0;
}
double r;
node A,B,C,O;
node AB,AC,AO;
double root(double a,double b,double c){//一元二次方程求根
return (-b-sqrt(b*b-4*a*c))/(2*a);
}
void getC(){//由起点,向量,得到C点坐标
double ao=A.dis(O);
double ac=root(1,-2*ao*cos(AC.agl(AO)),ao*ao-r*r);
C=A.add(AC.unt().mul(ac));
}
int judge(node a,node b,node c){//两个向量和平行于另一个向量
if(a.add(b).pal(c)==1)return 1;//向量同向
return 0;
}
int stop(){//线段在圆外
double a=B.dis(O);
double b=A.dis(O);
if(a<r||b<r)return 1;
double c=A.dis(B);
double p=(a+b+c)/2;
double s=sqrt(p*(p-a)*(p-b)*(p-c));//海伦公式
if(c>a&&c>b){//关键点
if(2*s/c<r)return 1;
return 0;
}
return 0;
}
int conet(){//如果从A直接到B
if(AC.pal(AB)==1)return 1;//两向量同向
return 0;
}
int work(){
AB={B.x-A.x,B.y-A.y};
AO={O.x-A.x,O.y-A.y};
if(stop())return 0;
if(conet())return 1;
getC();//得到C的坐标
node CB={B.x-C.x,B.y-C.y};
node OC={C.x-O.x,C.y-O.y};
if(judge(AC.neg().unt(),CB.unt(),OC.unt()))return 1;
return 0;
}
int main(){
int T;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++){//反射点C的坐标未知
scanf("%lf%lf%lf",&O.x,&O.y,&r);
scanf("%lf%lf%lf%lf",&A.x,&A.y,&AC.x,&AC.y);
scanf("%lf%lf",&B.x,&B.y);
printf("Case #%d: ",kase);
if(work())printf("Yes\n");
else printf("No\n");
}
return 0;
}