题目描述
小歪正在水底潜水,他所在的位置距离水面的直线距离为 。小歪有一个神奇的激光装置,激光射向水面后会发生全反射现象。
以小歪所在的位置为原点建立三维坐标轴,小歪的坐标即为 (0,0,0) 。在水中,有一些坐标需要小歪使用激光击中,第 i 个坐标使用 (xi,yi,zi)表示。求解,对于每一个坐标,小歪需要以什么向量方向射出激光,使得经过一次水面全反射后恰好击中它。
输入描述:
第一行输入两个整数 n,h(1≦n≦100; 1≦h≦109) 代表需要击中的坐标位置数量、距离水面的距离。随后 n 行,每行输入三个整数 x,y,z(1≦x,y≦109;−109≦z≦h)代表需要击中的坐标。
输出描述:
对于每一个坐标,在一行上输出三个整数 i,j,k代表射出向量方向,你需要保证 gcd(i,j,k)=1 。
示例:
输入
2 5
3 3 2
4 4 0
输出
3 3 8
2 2 5
解题思路:
激光入射的路径是从小歪的位置(0,0,0) 出发,反射后进入目标点。水面对称性说明,目标点在水面上的“对称点” (x,y,2h−z) 会是激光直线的延长线上的点。因此,只需要求解从 (0,0,0) 到对称点 (x,y,2h−z) 的向量方向,并化简为最简整数比即可。
代码:
#include <stdio.h>
#include <math.h>
//计算两个数的最大公约数
long long gcd(long long a,long long b)
{
if(a==0)
return fabs(b);
if(b==0)
return fabs(a);
while(b)
{
int r=a%b;
a=b;
b=r;
}
return fabs(a);
}
//计算三个数的最大公约数
long long gcd3(long long a,long long b,long long c)
{
return gcd(gcd(a,b),c);
}
int main ()
{
long long n,h;
scanf("%lld %lld",&n,&h);
while(n--)
{
long long x,y,z;
scanf("%lld %lld %lld",&x,&y,&z);
long long X,Y,Z;
X=x,Y=y,Z=2*h-z;
long long num=gcd3(X,Y,Z);
X/=num,Y/=num,Z/=num;
printf("%lld %lld %lld\n",X,Y,Z);
}
}
注意事项:
1.在处理最大公约数时,需要考虑负数或 0 的情况,可能导致化简结果错误。
2.计算2*h−z 时可能会导致溢出。