UVa 10488 Swimming Gopher

题目描述

一只囊地鼠需要从起点 (xs,ys)(x_s, y_s)(xs,ys) 移动到终点 (xt,yt)(x_t, y_t)(xt,yt),途中会遇到多个被水淹没的沟渠。坐标系中,xxx 轴从西向东,yyy 轴从南向北。

干燥陆地的分布有特殊的规律:对于任意整数 nnn,当 n×D+L≤y≤(n+1)×D−Ln \times D + L \leq y \leq (n+1) \times D - Ln×D+Ly(n+1)×DL 时,点 (x,y)(x, y)(x,y) 位于干燥陆地上。沟渠位于这些干燥带之间,每条沟渠的宽度为 2L2L2L

囊地鼠的目标是:

  1. 最小化游泳距离(穿过沟渠的总宽度)
  2. 在满足条件 111 的前提下,最小化在干燥陆地上的行走距离

给定 DDD, LLL, xsx_sxs, ysy_sys, xtx_txt, yty_tyt,求囊地鼠的最优路线。

输入格式

每行包含 666 个实数:DDD, LLL, xsx_sxs, ysy_sys, xtx_txt, yty_tyt

输出格式

对于每组输入,输出一行,格式为:

The gopher has to swim {swim_dist} meters and walk {walk_dist} meters.

题目分析

关键观察

  1. 游泳距离的确定性

    • 游泳距离只取决于必须穿过的沟渠数量
    • 从起点所在的带到终点所在的带,必须穿过 k=∣ns−nt∣k = |n_s - n_t|k=nsnt 条沟渠
    • 每条沟渠宽度为 2L2L2L,因此最小游泳距离为 k×2Lk \times 2Lk×2L
  2. 几何本质

    • 为了保持最小游泳距离,必须在每个沟渠处垂直游泳
    • 这相当于将每个游泳段"压缩"掉,将终点向起点方向移动总游泳距离
    • 最优行走路径就是连接起点和虚拟终点的直线

数学模型

设起点所在的带编号为 ns=⌊ys/D⌋n_s = \lfloor y_s / D \rfloorns=ys/D,终点所在的带编号为 nt=⌊yt/D⌋n_t = \lfloor y_t / D \rfloornt=yt/D,则:

  • 必须穿过的沟渠数量:k=∣ns−nt∣k = |n_s - n_t|k=nsnt
  • 游泳距离:swim=k×2Lswim = k \times 2Lswim=k×2L
  • 虚拟终点的 yyy 坐标:
    • 如果 ns<ntn_s < n_tns<nt(向上走):yv=yt−k×2Ly_v = y_t - k \times 2Lyv=ytk×2L
    • 如果 ns>ntn_s > n_tns>nt(向下走):yv=yt+k×2Ly_v = y_t + k \times 2Lyv=yt+k×2L
    • 如果 ns=ntn_s = n_tns=ntyv=yty_v = y_tyv=yt
  • 行走距离:walk=(xt−xs)2+(yv−ys)2walk = \sqrt{(x_t - x_s)^2 + (y_v - y_s)^2}walk=(xtxs)2+(yvys)2

算法思路

  1. 计算起点和终点所在的带编号
  2. 计算必须穿过的沟渠数量 kkk
  3. 计算游泳距离 k×2Lk \times 2Lk×2L
  4. 根据行进方向计算虚拟终点的 yyy 坐标
  5. 计算起点到虚拟终点的欧几里得距离作为行走距离

复杂度分析

  • 时间复杂度:O(1)O(1)O(1),只有常数次计算
  • 空间复杂度:O(1)O(1)O(1),只使用常数个变量

代码实现

// Swimming Gopher
// UVa ID: 10488
// Verdict: Accepted
// Submission Date: 2025-11-16
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

int main() {
    double D, L, xs, ys, xt, yt;
    while (cin >> D >> L >> xs >> ys >> xt >> yt) {
        int k = abs((int)floor(ys / D) - (int)floor(yt / D));
        double swim = k * 2 * L;
        double yv = yt - (yt > ys ? k * 2 * L : -k * 2 * L);
        double walk = hypot(xt - xs, yv - ys);
        printf("The gopher has to swim %.2lf meters and walk %.2lf meters.\n", swim, walk);
    }
    return 0;
}

样例验证

样例1

输入:100.0 10.0 0.0 50.0 100.0 50.0
输出:The gopher has to swim 0.00 meters and walk 100.00 meters.
  • 起点和终点在同一带,无需游泳
  • 行走距离为直线距离 100.00100.00100.00

样例2

输入:100.0 10.0 0.0 50.0 100.0 150.0
输出:The gopher has to swim 20.00 meters and walk 128.06 meters.
  • k=1k = 1k=1,游泳距离 20.0020.0020.00
  • 虚拟终点 yyy 坐标:150−20=130150 - 20 = 13015020=130
  • 行走距离:1002+(130−50)2=10000+6400≈128.06\sqrt{100^2 + (130-50)^2} = \sqrt{10000 + 6400} \approx 128.061002+(13050)2=10000+6400128.06

样例3

输入:100.0 10.0 0.0 -50.0 100.0 50.0
输出:The gopher has to swim 20.00 meters and walk 128.06 meters.
  • k=1k = 1k=1,游泳距离 20.0020.0020.00
  • 虚拟终点 yyy 坐标:50−20=3050 - 20 = 305020=30
  • 行走距离:1002+(30−(−50))2=10000+6400≈128.06\sqrt{100^2 + (30-(-50))^2} = \sqrt{10000 + 6400} \approx 128.061002+(30(50))2=10000+6400128.06

样例4

输入:100.0 10.0 0.0 -50.0 100.0 150.0
输出:The gopher has to swim 40.00 meters and walk 188.68 meters.
  • k=2k = 2k=2,游泳距离 40.0040.0040.00
  • 虚拟终点 yyy 坐标:150−40=110150 - 40 = 11015040=110
  • 行走距离:1002+(110−(−50))2=10000+25600≈188.68\sqrt{100^2 + (110-(-50))^2} = \sqrt{10000 + 25600} \approx 188.681002+(110(50))2=10000+25600188.68

总结

本题的关键在于理解几何变换的本质:将固定的游泳距离"压缩"后,问题转化为在干燥陆地上寻找起点到虚拟终点的最短直线路径。这种思路不仅简化了计算,还体现了优化问题中常见的"问题转化"思想。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值