Решение покажу на Пайтоне.
Идея тривиальна. Нужно перейти в систему отсчёта, связанную с бегунком, и повернуть оси так, чтобы точка старта перехватчика находилась на оси Ox
:

Решатель:
# Решатель задачи догона
# r0 - начальное положение бегунка
# rV - вектор скорости бегунка
# cVAbs - модуль скорости перехватчика
# Возвращает вектор скорости перехватчика и время погони
# Если задача не решается, то выбрасывает исключение
def solve(r0:Vector, rV:Vector, cVAbs:float) -> tuple(Vector,float):
if abs(r0) == 0.0:
raise ValueError("Уже догнал")
if cVAbs < 0.0:
raise ValueError("Отрицательная скорость", cVAbs)
# Перейти в систему отсчёта бегунка
# Поворот системы координат
sin = r0.y/abs(r0)
cos = r0.x/abs(r0)
c0 = -r0.rot_sin_cos(sin, cos)
v0 = -rV.rot_sin_cos(sin, cos)
# Догонный курс вдоль оси Ох'
v_y = -v0.y
v_x_sq = cVAbs*cVAbs - v_y*v_y
if v_x_sq < 0:
# При заданном модуле скорости перехватчик никогда не догонит бегунка
raise ValueError("Нет решения")
v_x = math.sqrt(v_x_sq)
# Выбор направления - v_x и c_0 должны быть разных знаков
if c0.x > 0:
v_x = -v_x
# Скорость сближения
u = v0.x + v_x
t = abs(c0.x/u)
v_rotated = Vector(v_x, v_y)
# Поворот системы координат обратно
v = v_rotated.rot_sin_cos(-sin, cos)
return v,t
Решатель возвращает вектор скорости v
и время перехвата t
. Так как перехватчик стартует из начала координат, то точка перехвата будет v*t
.
Проверка
r0 = Vector(1,1)
rV = Vector(1,0)
cV = 1.5
v, t = solve(r0, rV, cV)
print("Начальная точка: ", r0, ", начальная скорость: ", rV)
print("Результат: скорость ", v,abs(v),", время преследования, секунды: ", t)
print("Положение бегунка", r0+rV*t)
print("Положение преследователя", v*t)
r0 = Vector(1,1)
rV = Vector(-1,0)
cV = 1.5
v, t = solve(r0, rV, cV)
print("Начальная точка: ", r0, ", начальная скорость: ", rV)
print("Результат: скорость ", v,abs(v),", время преследования, секунды: ", t)
print("Положение бегунка", r0+rV*t)
print("Положение преследователя", v*t)
Результаты:
Начальная точка: Vector(1.000000,1.000000) , начальная скорость: Vector(1.000000,0.000000)
Результат: скорость Vector(1.435414,0.435414) 1.4999999999999998 , время преследования, секунды: 2.296662954709576
Положение бегунка Vector(3.296663,1.000000)
Положение преследователя Vector(3.296663,1.000000)
Начальная точка: Vector(1.000000,1.000000) , начальная скорость: Vector(-1.000000,0.000000)
Результат: скорость Vector(0.435414,1.435414) 1.4999999999999998 , время преследования, секунды: 0.6966629547095765
Положение бегунка Vector(0.303337,1.000000)
Положение преследователя Vector(0.303337,1.000000)
Нетрудно видеть, что в момент перехвата координаты бегунка и перехватчика совпадают.
Решатель использует класс Vector
, который можно складывать, умножать на число, вычислять модуль и поворачивать.
# Двумерный вектор
class Vector:
def __init__(self, x:float, y:float) -> None:
self.x = x
self.y = y
# Сложение с вектором
def __add__(self, other:any) -> Vector:
if isinstance(other, Vector):
return Vector(self.x+other.x, self.y+other.y)
raise ValueError("Not a vector", other)
# Умножение на число справа, до кучи скалярное произведение (не понадобилось)
def __mul__(self, other) -> Vector:
if isinstance(other, float) or isinstance(other, int):
return Vector(self.x*other, self.y*other)
if isinstance(other, Vector):
return self.x*other.x + self.y*other.y
raise ValueError("Not a number", other)
# Деление на число
def __div__(self, other) -> Vector:
if isinstance(other, float) or isinstance(other, int):
return Vector(self.x/other, self.y/other)
raise ValueError("Not a number", other)
# Умножение на число слева
def __rmul__(self, other) -> Vector:
if isinstance(other, float) or isinstance(other, int):
return Vector(self.x*other, self.y*other)
raise ValueError("Not a number", other)
# Унарный минус
def __neg__(self):
return Vector(-self.x, -self.y)
# Модуль
def __abs__(self):
return math.sqrt(self.x*self.x + self.y*self.y)
# Поворот
def rot_sin_cos(self, sin : float, cos: float) -> Vector:
return Vector(self.x*cos + self.y*sin, self.y*cos - self.x*sin)
# ToString
def __repr__(self) -> str:
return "Vector(%f,%f)"%(self.x, self.y)