原题链接:台球碰撞
解题思路:
(1)传送面板:https://blog.dotcpp.com/a/63859
思路和这个差不多,这个人写的很详细,而且我 debug 时还参考了这个人的代码,直接看他的就完事了。
(2)本题的难度在于建模而不是算法,只要搞清楚数学公式就好写了,剩下的就是细心。
(3)核心思想:对移动的绝对距离来说,台球每移动 2L 相当于没动,这个 L 指的是台球桌的边长,需要在 x 轴和 y 轴分开考虑,即 2L 和 2W。
此外,台球有体积,要注意半径的影响。减去周期后最后剩 2 种情况:[0, L] 和 (L, 2L],分开考虑。
注意事项:
(1)角度转弧度别用 #define pi 3.1415 了,用 acos(-1) 表示 PI。
(2)减去周期后最后简化为 2 种情况:一次没反弹和反弹一次。
(3)构建新球桌时减去的 R 要在最后补上。
参考代码:
// 题目 1075: 台球碰撞
#include <iostream>
#include <cmath>
#include <iomanip>
#define pi 3.1415 // 精度不够,会导致答案错误
using namespace std;
int main() {
int L, W; // 台球桌长宽
int x, y, R; // 初始球心位置和台球半径
int a, v, s; // 初始角度,速度,经过时间
double resX, resY; // 最终球心位置
while (cin >> L >> W >> x >> y >> R >> a >> v >> s) {
if (!L) {
break; // 球桌长度不可能为0,为0说明是结束输入的标志
}
// 考虑球的碰撞体积后的实际台球桌,球心到达新的球桌边缘时球的边缘碰到旧的球桌边缘
L -= 2 * R;
W -= 2 * R;
x -= R;
y -= R;
double arc = a * acos(-1) / 180; // 正确的角度转弧度
// 球距离原点的总位移,必须取绝对值
double length = fabs(x + v * s * cos(arc));
double width = fabs(y + v * s * sin(arc));
// 每移动2L实际坐标没变
while (length > 2 * L ) {
length -= 2 * L;
}
while (width > 2 * W) {
width -= 2 * W;
}
// <= L 说明去除周期运动后,球实际上移动的距离尚未触发反弹
// > L && <= 2L 说明球实际上相当于只触发了一次反弹
// W 同理
if (length <= L) {
resX = length + R;
} else {
resX = 2 * L - length + R;
}
if (width <= W) {
resY = width + R;
} else {
resY = 2 * W - width + R;
}
cout << fixed << setprecision(2) << resX << " " << resY << endl;
} // end while
return 0;
}0.0分
7 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复