题目:给一个圆和圆外两点A、B,A以给定的速度出发,若碰到圆则发生完全弹性碰撞,问能否经过B。
思路:分类讨论1:A的路径碰到了圆,找出两条射线判断是否经过B点。2:A的路径没有碰到了圆,判断一条射线是否经过B点。
精度是真的麻烦。。
#include<bits/stdc++.h>
using namespace std;
typedef long double ldouble;
const ldouble eps = 1e-8;
const ldouble inf = 1e20;
const ldouble pi = acos(-1.0);
const int maxp = 1010;
int sgn(ldouble x){
if(fabs(x) < eps)return 0;
if(x < 0)return-1;
else return 1;
}
inline ldouble sqr(ldouble x){return x*x;}
struct Point{
ldouble x,y;
Point(){}
Point(ldouble _x,ldouble _y){
x = _x;
y = _y;
}
void input(){
scanf("%lf%lf",&x,&y);
}
void output(){
printf("%.2f-%.2f\n",x,y);
}
bool operator == (Point b)const{
return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
}
bool operator < (Point b)const{
return sgn(x-b.x)== 0-sgn(y-b.y)?0:x<b.x;
}
Point operator-(const Point &b)const{
return Point(x-b.x,y-b.y);
}
//叉积
ldouble operator ^(const Point &b)const{
return x*b.y-y*b.x;
}
//点积
ldouble operator *(const Point &b)const{
return x*b.x + y*b.y;
}
//返回长度
ldouble len(){
return hypot(x,y);//库函数
}
//返回长度的平方
ldouble len2(){
return x*x + y*y;
}
//返回两点的距离
ldouble distance(Point p){
return hypot(x-p.x,y-p.y);
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator *(const ldouble &k)const{
return Point(x*k,y*k);
}
Point operator /(const ldouble &k)const{
return Point(x/k,y/k);
}
//化为长度为 r 的向量
Point trunc(ldouble r){
ldouble l = len();
if(!sgn(l))return *this;
r /= l;
return Point(x*r,y*r);
}
};
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e){
s = _s;
e = _e;
}
bool operator ==(Line v){
return (s == v.s)&&(e == v.e);
}
//求线段长度
ldouble length(){
return s.distance(e);
}
// 点在线段上的判断
bool pointonseg(Point p){
return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
}
//点到直线的距离
ldouble dispointtoline(Point p){
return fabs((p-s)^(e-s))/length();
}
//点到线段的距离
ldouble dispointtoseg(Point p){
if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
return min(p.distance(s),p.distance(e));
return dispointtoline(p);
}
//返回点 p 在直线上的投影
Point lineprog(Point p){
return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) );
}
//返回点 p 关于直线的对称点
Point symmetrypoint(Point p){
Point q = lineprog(p);
return Point(2*q.x-p.x,2*q.y-p.y);
}
};
struct circle{
Point p;//圆心
ldouble r;//半径
circle(){}
circle(Point _p,ldouble _r){
p = _p;
r = _r;
}
circle(ldouble x,ldouble y,ldouble _r){
p = Point(x,y);
r = _r;
}
bool operator == (circle v){
return (p==v.p) && sgn(r-v.r)==0;
}
bool operator < (circle v)const{
return ((p<v.p)||((p==v.p)&&sgn(r-v.r)<0));
}
//直线和圆的关系
//比较的是圆心到直线的距离和半径的关系
int relationline(Line v){
ldouble dst = v.dispointtoline(p);
if(sgn(dst-r) < 0)return 2;
else if(sgn(dst-r) == 0)return 1;
return 0;
}
//求直线和圆的交点,返回交点个数
int pointcrossline(Line v,Point &p1,Point &p2){
if(!(*this).relationline(v))return 0;
Point a = v.lineprog(p);
ldouble d = v.dispointtoline(p);
d = sqrt(r*r-d*d);
if(sgn(d) == 0){
p1 = a;
p2 = a;
return 1;
}
p1 = a + (v.e-v.s).trunc(d);
p2 = a-(v.e-v.s).trunc(d);
return 2;
}
};
Point pa,pb,c;
Line l1,l2,l0;
circle cc;
ldouble dx,dy,r;
int main()
{
// freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
int cas=0;
while(t--)
{
int flag=0;
//scanf("%lf%lf%lf",&c.x,&c.y,&r);
cin>>c.x>>c.y>>r;
//scanf("%lf%lf%lf%lf",&pa.x,&pa.y,&dx,&dy);
cin>>pa.x>>pa.y>>dx>>dy;
//scanf("%lf%lf",&pb.x,&pb.y);
cin>>pb.x>>pb.y;
pa.x-=c.x;pa.y-=c.y;
pb.x-=c.x;pb.y-=c.y;
c.x=c.y=0;
l0.s=pa;
l0.e.x=pa.x+dx*10000; l0.e.y=pa.y+dy*10000;
cc.p.x=c.x,cc.p.y=c.y,cc.r=r;
Point p1,p2;
int tmp=cc.pointcrossline(l0,p1,p2);
Point ap;
ap.x=pa.x+dx*0.001; ap.y=pa.y+dy*0.001;
if(tmp==2&&ap.x*ap.x+ap.y*ap.y<pa.x*pa.x+pa.y*pa.y)
{
if(sgn(pa.distance(p1)-pa.distance(p2))>0)
swap(p1,p2);
l1.s=pa,l1.e=p1;
Line lk;
lk.s=c,lk.e=p1;
pa.x-=10000*dx; pa.y-=10000*dy;
Point paa=lk.symmetrypoint(pa);
l2.s=p1;l2.e=paa;
if(l1.pointonseg(pb)||l2.pointonseg(pb))
flag=1;
}
else
if(l0.pointonseg(pb))
flag=1;
if(flag)
printf("Case #%d: Yes\n",++cas);
else
printf("Case #%d: No\n",++cas);
}
return 0;
}