林惜城


私信TA

用户名:reminder

访问量:27305

签 名:

等  级
排  名 94
经  验 8447
参赛次数 0
文章发表 95
年  龄 0
在职情况 学生
学  校 西安电子科技大学
专  业

  自我简介:

哈姆


解题思路:

(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分

9 人评分

看不懂代码?想转换其他语言的代码? 或者想问其他问题? 试试问问AI编程助手,随时响应你的问题:

编程语言转换

万能编程问答

代码解释器

  评论区

这个题目如果确实按出题限定了s<=105,那么按反弹后方向相反求解就可以了。但是,测试数据中s很大,导致反弹精确时间以及sin,cos取值差异,造成小数点上的数据有误差而出错。
2023-10-30 16:23:10
  • «
  • 1
  • »