【题目大意】
给定n个球,与一条射线,然后让你模拟这个射线在这些球之间弹,输出弹到得球的标号。如果弹到<=10个就有多少输出多少。否则,输出前10个+ 'etc.'
【算法分析】
我们用三维向量来解决。
1、首先根据点到球心距离等于半径 + 我们的运动向量列出一个方程,解这个一元二次方程可以得到我们什么时候碰到这个球。
2、然后碰到以后呢。就把射线起点,球上的碰触点,球心这三个点,搞成一个平面,然后再在上面以向量:碰触点->球心作为法线,考虑镜面反射即可。
然后这里我再次用了一个解方程+向量伸缩的方法得到了他反射以后的向量。
关于第二步的反射部分,我们所知道的条件有:入射向量,法线向量。我的做法具体就是先构造出向量tmp=发现向量-入射向量。并使得|tmp|=|入射向量|。然后就可以通过一些几何知识来搞了。
【其它】WA了几遍,因为我解一元二次方程的时候判断无解写得是delta<1e-6,然后如果1e-6<=delta<0的话,我就先将它置为0再进行后面的计算。
我改成delta<0就为无解就AC了。T_T。。。精度什么的,最讨厌了。
【CODE】
#include
#define Sqr(x) ((x)*(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
const int N=1005;
const double eps=1e-6;
int n;
double res1,res2;
struct Circle{double x,y,z,r;}a[N];
struct Point{double x,y,z;}p,fx;
void init(){
scanf("%d",&n);
int i,j;
for (i=1;i<=n;i++)
cin >> a[i].x >> a[i].y >> a[i].z >> a[i].r;
cin >> p.x >> p.y >> p.z >> fx.x >> fx.y >> fx.z;
fx.x-=p.x;
fx.y-=p.y;
fx.z-=p.z;
}
Point Get_Point(double rate){
Point res;
res.x=fx.x*rate+p.x;
res.y=fx.y*rate+p.y;
res.z=fx.z*rate+p.z;
return res;
}
double Get_Meet_Rate(Circle Cir){
double a,b,c,delta,x1,x2;
Point tmp;
tmp.x=Cir.x-p.x;
tmp.y=Cir.y-p.y;
tmp.z=Cir.z-p.z;
a=Sqr(fx.x)+Sqr(fx.y)+Sqr(fx.z);
b=-2*(fx.x*tmp.x + fx.y*tmp.y + fx.z*tmp.z);
c=-Sqr(Cir.r)+Sqr(tmp.x)+Sqr(tmp.y)+Sqr(tmp.z);
delta=b*b-4*a*c;
if (delta<0) return 1e22;
delta=sqrt(delta);
x1=(-b+delta)/(2*a);
x2=(-b-delta)/(2*a);
if (x1<=eps) x1=1e22;
if (x2<=eps) x2=1e22;
res1=x1; res2=x2;
return min(x1,x2);
}
Point opposite(Point tmp){
Point res;
res.x=-tmp.x;
res.y=-tmp.y;
res.z=-tmp.z;
return res;
}
void Reflect(int i,double rate){
Point cross=Get_Point(rate);
Get_Meet_Rate(a[i]);
if ( fabs(res1-res2) < eps ){
p=cross;
return;
}
Point normal_line,tmp;
normal_line.x=(a[i].x-cross.x)/2;
normal_line.y=(a[i].y-cross.y)/2;
normal_line.z=(a[i].z-cross.z)/2;
double t=Sqr(normal_line.x)+Sqr(normal_line.y)+Sqr(normal_line.z);
t/=(normal_line.x*fx.x + normal_line.y*fx.y + normal_line.z*fx.z);
fx.x*=t; fx.y*=t; fx.z*=t;
normal_line.x*=2;
normal_line.y*=2;
normal_line.z*=2;
tmp.x=normal_line.x-fx.x;
tmp.y=normal_line.y-fx.y;
tmp.z=normal_line.z-fx.z;
fx=opposite(tmp);
p=cross;
bool flag=false;
if (fx.x>10) flag=true;
if (fx.y>10) flag=true;
if (fx.z>10) flag=true;
if (!flag){
fx.x*=10;
fx.y*=10;
fx.z*=10;
}
}
void work(){
int i,best,cnt=0;
double rate,tmp;
while (1){
rate=1e20;
best=0;
for (i=1;i<=n;i++){
tmp=Get_Meet_Rate(a[i]);
if (tmp
best=i;
}
}
if (best==0) break;
Reflect(best,rate);
cnt++;
if (cnt>10) break;
if (cnt!=1) cout << " ";
cout << best;
}
if (cnt>10) cout << " etc." << endl;
else cout << endl;
}
int main(){
init();
work();
return 0;
}
精度什么的,最讨厌了被精度虐杀了无数次的羞愧的路过 !!!!!!!!!!!!!!!!