样例输入
100 100 80 10 5 90 2 23
110 100 70 10 5 180 1 9999
0 0 0 0 0 0 0 0
样例输出
80.00 56.00
71.00 10.00
思路(参考BornFated的思路)(【BornFated】1075_台球碰撞_C语言题解-Dotcpp编程社区):
A.本题的主要问题在于建模而不是编程,涉及到球在二维平面内的受边界限制的斜向运动
由于球在碰撞时,被碰的是球表面,所以我们考虑重新建立坐标系,具体如下
如图,矩形的两边边长都缩短了2R,此时我们便可以把球体抽象成一个质点。
B.由于球体做斜向运动,我们考虑将其运动进行分解,分开处理
先处理X轴,如图
由于题目中的起始坐标x不一定在原点上,所以我们可以把它看成从原点出发移动x个单位的运动,由于初速度方向不定,从原点出发, 无论是向左运动还是向右运动,它都会变成向右运动(向左瞬间碰壁反弹)举个例子:假设质点从 3 开始发生-27的位移,也就相当于是从原点开始发生了(-27+3)=(-24)的位移,也就相当于从原点开始发生了24的总位移,
值得注意的是,一旦总位移大于两倍的边长,它的实际位移就应该减去一个两倍边长,实际上,边界范围的两倍是一个周期。
综上所述:假设初始坐标为 x ,移动位移为 s ,边界长度为 L ,那么求解最终坐标的方法就是:先求出转化后的从原点出发的总位移 Dx,Dx=fabs(x+s),之后若 Dx 大于 2L 则 Dx-=2L 直到 Dx小于2L,最后若 Dx小于L 则 Dx 即最终坐标,若 Dx介于2L和L之间 ,那么最终坐标为 2L-Dx 。
最后把该思路推广到y轴上,便可以得出结论
代码如下:
#include<stdio.h>
#include<math.h>
void ZB(double L, double W, double x, double y, double R, double a, double v, double s, double Dx, double Dy);
int main()
{
double L[26], W[26], x[26], y[26], R[26], a[26], v[26], s[26];
double Dx = 0, Dy = 0;
int i,j=0;
for ( i = 0; i < 26; i++)
{
scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &L[i], &W[i], &x[i], &y[i], &R[i], &a[i], &v[i], &s[i]);
if (L[i] == 0 && W[i] == 0 && x[i] == 0 && y[i] == 0 && R[i] == 0 && a[i] == 0 && v[i] == 0 && s[i] == 0)
{
j = i;
break;
}
}
for ( i = 0; i < j; i++)
{
ZB(L[i], W[i], x[i], y[i], R[i], a[i], v[i], s[i],Dx,Dy);
}
return 0;
}
void ZB(double L, double W, double x, double y, double R, double a, double v, double s,double Dx,double Dy)
{
double l, w, x0, y0;
a = a / 180.0 * acos(-1);
l = L - 2 * R;
w = W - 2 * R;
x0 = x - R;
y0 = y - R;
Dx = fabs(v * s * cos(a) + x0);
Dy = fabs(v * s * sin(a) + y0);
while (Dx > 2 * l)
{
Dx -= 2 * l;
}
while (Dy > 2 * w)
{
Dy -= 2 * w;
}
if (Dx > l && Dx < 2 * l) Dx = 2 * l - Dx;
else;
if (Dy > w && Dy < 2 * w) Dy = 2 * w - Dy;
else;
printf("%.2lf %.2lf\n", Dx + R, Dy + R);
}