出発地点から目的地までの距離を とする。歩いて直行する場合の時間は である。ジャンプは方向にかかわらず必ず距離 だけ移動し、時間 がかかる。残りの距離は歩いて移動できる。
、 とおくと、 である。候補となる時間は次のとおり。
- 最初から最後まで歩く: 。
- 目的地の方向へ 回ジャンプし、残りの を歩く: 。
- 目的地の方向へ 回ジャンプし、行き過ぎた距離 を戻って歩く: 。
- 回ジャンプして目的地に到達する: 。 なら、目的地の方向へ 回ジャンプしたあと、2回のジャンプの合成変位を にする。長さ のジャンプ2回で作れる合成変位の長さは から までであり、 なので実現できる。 の場合も、2回のジャンプで合成変位を にできるため、同じ時間で到達できる。
この候補で最小値を求められる。 回ジャンプする場合、残りの距離は少なくとも なので、時間は少なくとも である。これは の一次式だから、この範囲での最小値は端点の または で得られる。 回以上ジャンプすると、ジャンプ時間だけで少なくとも が必要であり、上記の方法で実際にその時間で到達できる。 の場合も同様に扱える。1回のジャンプ後に残る距離の最小値は で、2回のジャンプなら目的地に到達できる。したがって、 の場合や の場合も含め、列挙した候補の最小値が答えとなる。
C++17 の実装
hypot を使ってユークリッド距離を安定して計算する。時間計算量、追加領域計算量はいずれも である。
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
double x, y, jumpDistance, jumpTime;
std::cin >> x >> y >> jumpDistance >> jumpTime;
const double distance = std::hypot(x, y);
const auto q = static_cast<long long>(std::floor(distance / jumpDistance));
const double remainder = distance - q * jumpDistance;
double answer = distance;
if (q == 0) {
answer = std::min({answer,
jumpTime + jumpDistance - distance,
2.0 * jumpTime});
} else {
answer = std::min({answer,
q * jumpTime + remainder,
(q + 1) * jumpTime + jumpDistance - remainder,
(q + 1) * jumpTime});
}
std::cout << std::fixed << std::setprecision(10) << answer << '\n';
return 0;
}