先贴一下代码:
/************************************************
┆ ┏┓ ┏┓ ┆
┆┏┛┻━━━┛┻┓ ┆
┆┃ ┃ ┆
┆┃ ━ ┃ ┆
┆┃ ┳┛ ┗┳ ┃ ┆
┆┃ ┃ ┆
┆┃ ┻ ┃ ┆
┆┗━┓ ┏━┛ ┆
┆ ┃ ┃ ┆
┆ ┃ ┗━━━┓ ┆
┆ ┃ AC代马 ┣┓┆
┆ ┃ ┏┛┆
┆ ┗┓┓┏━┳┓┏┛ ┆
┆ ┃┫┫ ┃┫┫ ┆
┆ ┗┻ ┛ ┗┻┛ ┆
************************************************ */
#pragma warning (disable:4996)
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<stack>
#include<cstdlib>
#include<functional>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int Maxn = 2e5 + 10;
const int N = 100010;
double eps = 1e-4;
int hit(double ox,double oy ,double r,double ax,double ay,double vx,double vy,double &t)
{
double a=vx*vx+vy*vy;
double b=2*ax*vx-2*vx*ox+2*ay*vy-2*vy*oy;
double c=ax*ax+ox*ox-2*ax*ox+ay*ay+oy*oy-2*ay*oy-r*r;
double tmp=b*b-4*a*c;
if(tmp<=0) return 0;
double t1=(sqrt(tmp)-b)/(2*a),t2=-1.0*(sqrt(tmp)+b)/(2*a);
if(t1<=0 && t2<=0) return 0;
t=min(t1,t2);
return 1;
}
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
double ox,oy,r,ax,ay,vx,vy,bx,by;
scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&ox,&oy,&r,&ax,&ay,&vx,&vy,&bx,&by);
double pt;
if(!hit(ox,oy,r,ax,ay,vx,vy,pt)){
double t0;
if(vx!=0){
t0=(bx-ax)/vx;
}
else{
t0=(by-ay)/vy;
}
if(fabs(bx-ax-vx*t0)<eps && fabs(by-ay-vy*t0)<eps){
printf("Case #%d: Yes\n",cas);
}
else{
printf("Case #%d: No\n",cas);
}
}
else{
double t0;
if(vx!=0){
t0=(bx-ax)/vx;
}
else{
t0=(by-ay)/vy;
}
if(fabs(bx-ax-vx*t0)<eps && fabs(by-ay-vy*t0)<eps && t0>=0 && t0<=pt){
printf("Case #%d: Yes\n",cas);
continue;
}
double x1=ax+vx*pt,y1=ay+vy*pt;
double x2=ox,y2=oy;
double a=y2-y1,b=x1-x2,c=y1*x2-x1*y2;
double px1=ax,py1=ay;
double px2=((b*b-a*a)*px1-2*a*b*py1-2*a*c)/(a*a+b*b);
double py2=((a*a-b*b)*py1-2*a*b*px1-2*b*c)/(a*a+b*b);
double vx2=(px2-x1)/t,vy2=(py2-y1)/t;
if(vx2!=0){
t0=(bx-x1)/vx2;
}
else{
t0=(by-y1)/vy2;
}
if(t0>=0 && fabs(bx-x1-vx2*t0)<eps && fabs(by-y1-vy2*t0)<eps){
printf("Case #%d: Yes\n",cas);
}
else{
printf("Case #%d: No\n",cas);
// printf("%.2f %.2f\n",x1,y1);
// printf("%.2f %.2f\n",vx2,vy2);
}
}
}
return 0;
}
首先分成和圆碰撞和不与圆碰撞两种情况:
1.点A和圆不碰撞,这个很好判断
上面是射线的轨迹方程,下面是圆的轨迹方程,合并,求解t,若t无解或仅有一个解(即bb-4a*c<=0),直接判断B是否在A的轨迹上
2.若A的轨迹和圆有两个交点,B可以在A去碰撞圆的轨迹上,也可以在A碰撞完圆后的轨迹上。碰撞圆的轨迹上很好判断。下面说说B在碰撞后的轨迹上的求法,求出碰撞点,过碰撞点和圆心作直线L,求起始点关于直线L的对称点(px,py),有了碰撞点、起始点,还有对称点(px,py),不难求碰撞后的轨迹方程。
两点式:(y-y2)/(y1-y2) = (x-x2)/(x1-x2)得出直线L
对称点公式: