UVa 11768 Lattice Point or Not

题目分析

本题要求计算连接两个给定点的线段上格点(整数坐标点)的数量。与经典格点问题不同的是,本题的输入坐标可能是含一位小数的浮点数,这给问题带来了一定复杂性。

关键理解

  1. 格点定义:在笛卡尔坐标系中,坐标 ( x , y ) (x, y) (x,y) 均为整数的点。
  2. 线段上的格点:位于线段上(包括两个端点)且坐标为整数的点。
  3. 输入特殊性:坐标值范围 ∣ x ∣ , ∣ y ∣ ≤ 200000 |x|, |y| \leq 200000 x,y200000,且小数点后恰好有一位数字

解题思路分析

第一步:消除小数影响

由于输入坐标只有一位小数,我们可以将所有坐标乘以 10 10 10,转化为整数坐标进行处理。例如:

  • 原始坐标 ( 10.1 , 10.1 ) (10.1, 10.1) (10.1,10.1) → 转换后 ( 101 , 101 ) (101, 101) (101,101)
  • 原始坐标 ( 11.2 , 11.2 ) (11.2, 11.2) (11.2,11.2) → 转换后 ( 112 , 112 ) (112, 112) (112,112)

这样做的目的是避免浮点数精度问题,将所有计算都放在整数域进行。

第二步:线段参数化表示

设转换后的整数坐标为:

  • P 1 = ( X 1 , Y 1 ) P_1 = (X_1, Y_1) P1=(X1,Y1)
  • P 2 = ( X 2 , Y 2 ) P_2 = (X_2, Y_2) P2=(X2,Y2)

线段上的点可以表示为:
P ( t ) = ( X 1 + t ⋅ d x ,   Y 1 + t ⋅ d y ) P(t) = (X_1 + t \cdot dx,\ Y_1 + t \cdot dy) P(t)=(X1+tdx, Y1+tdy)
其中:

  • d x = X 2 − X 1 dx = X_2 - X_1 dx=X2X1
  • d y = Y 2 − Y 1 dy = Y_2 - Y_1 dy=Y2Y1
  • t t t 为参数,且 0 ≤ t ≤ g 0 \leq t \leq g 0tg,其中 g = gcd ⁡ ( ∣ d x ∣ , ∣ d y ∣ ) g = \gcd(|dx|, |dy|) g=gcd(dx,dy)

这里 g + 1 g+1 g+1 表示线段上等分点的数量(在放大10倍的坐标系中)。

第三步:筛选真正格点

虽然线段上有 g + 1 g+1 g+1 个等分点,但只有那些坐标能被 10 10 10 整除的点才是原坐标系中的整数格点。因为:

  • 放大10倍后坐标为 ( X , Y ) (X, Y) (X,Y)
  • 原坐标为 ( x , y ) = ( X / 10 , Y / 10 ) (x, y) = (X/10, Y/10) (x,y)=(X/10,Y/10)
  • 只有当 X % 10 = 0 X \% 10 = 0 X%10=0 Y % 10 = 0 Y \% 10 = 0 Y%10=0 时, ( x , y ) (x, y) (x,y) 才是整数坐标

因此,算法流程为:

  1. 遍历所有等分点 t = 0 , 1 , 2 , … , g t = 0, 1, 2, \dots, g t=0,1,2,,g
  2. 对每个点计算坐标 ( X , Y ) (X, Y) (X,Y)
  3. 检查是否满足 X % 10 = 0 X \% 10 = 0 X%10=0 Y % 10 = 0 Y \% 10 = 0 Y%10=0
  4. 统计满足条件的点数
第四步:特殊处理
  • 两点重合情况:如果 d x = 0 dx = 0 dx=0 d y = 0 dy = 0 dy=0,则线段退化为一个点。此时只需检查该点是否为整数格点。
  • 坐标相等情况:如果 d x = 0 dx = 0 dx=0 d y = 0 dy = 0 dy=0,算法依然适用,因为 gcd ⁡ \gcd gcd 函数能正确处理。

算法复杂度

  • 每组数据需要计算一次 gcd ⁡ \gcd gcd,时间复杂度 O ( log ⁡ ( max ⁡ ( ∣ d x ∣ , ∣ d y ∣ ) ) ) O(\log(\max(|dx|, |dy|))) O(log(max(dx,dy)))
  • 需要遍历 g + 1 g+1 g+1 个点进行检查,最坏情况下 g g g 可能达到 4 × 1 0 6 4 \times 10^6 4×106(当 ∣ d x ∣ = ∣ d y ∣ = 200000 × 10 |dx|=|dy|=200000 \times 10 dx=dy=200000×10 且互质时)
  • 但实际测试中 g g g 通常较小,算法能在时限内通过

数学原理

d x dx dx d y dy dy 的最大公约数为 g g g,则线段上整数点(在放大 10 10 10 倍的坐标系中)的坐标为:
( X 1 + d x g ⋅ t ,   Y 1 + d y g ⋅ t ) ,   t = 0 , 1 , 2 , … , g \left(X_1 + \frac{dx}{g} \cdot t,\ Y_1 + \frac{dy}{g} \cdot t\right),\ t = 0, 1, 2, \dots, g (X1+gdxt, Y1+gdyt), t=0,1,2,,g

这些点均匀分布在线段上,相邻点之间的 x x x 坐标差为 d x g \frac{dx}{g} gdx y y y 坐标差为 d y g \frac{dy}{g} gdy

代码实现

// Lattice Point or Not
// UVa ID: 11768
// Verdict: Accepted
// Submission Date: 2025-12-03
// UVa Run Time: 0.110s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

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

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        double x1, y1, x2, y2;
        scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
        
        // 乘以10转换为整数坐标,避免浮点误差
        int X1 = round(x1 * 10);
        int Y1 = round(y1 * 10);
        int X2 = round(x2 * 10);
        int Y2 = round(y2 * 10);
        
        int dx = X2 - X1;
        int dy = Y2 - Y1;
        
        // 处理两点重合的特殊情况
        if (dx == 0 && dy == 0) {
            if (X1 % 10 == 0 && Y1 % 10 == 0) printf("1\n");
            else printf("0\n");
            continue;
        }
        
        // 计算dx和dy的最大公约数
        int g = __gcd(abs(dx), abs(dy));
        dx /= g;  // x方向每步增量
        dy /= g;  // y方向每步增量
        
        int count = 0;  // 统计整数格点数量
        for (int t = 0; t <= g; t++) {
            int x = X1 + t * dx;
            int y = Y1 + t * dy;
            // 检查是否为原坐标系中的整数点
            if (x % 10 == 0 && y % 10 == 0) count++;
        }
        printf("%d\n", count);
    }
    return 0;
}

测试样例验证

样例输入

3
10.1 10.1 11.2 11.2
10.2 100.3 300.3 11.1
1.0 1.0 2.0 2.0

样例输出

1
0
2

分析

  1. 第一组 ( 10.1 , 10.1 ) (10.1, 10.1) (10.1,10.1) ( 11.2 , 11.2 ) (11.2, 11.2) (11.2,11.2)

    • 斜率接近1,线段上有且仅有一个整数格点 ( 11 , 11 ) (11, 11) (11,11)
  2. 第二组 ( 10.2 , 100.3 ) (10.2, 100.3) (10.2,100.3) ( 300.3 , 11.1 ) (300.3, 11.1) (300.3,11.1)

    • 线段上没有任何整数格点
  3. 第三组 ( 1.0 , 1.0 ) (1.0, 1.0) (1.0,1.0) ( 2.0 , 2.0 ) (2.0, 2.0) (2.0,2.0)

    • 端点本身就是整数格点,且线段上只有这两个整数格点

总结

本题的关键在于:

  1. 坐标转换:通过乘以 10 10 10 将一位小数坐标转换为整数坐标
  2. 参数化表示:利用最大公约数将线段等分,得到所有候选点
  3. 条件筛选:检查坐标是否能被 10 10 10 整除,确定是否为真正的整数格点

这种方法避免了浮点数比较的精度问题,将问题完全转化为整数计算,保证了算法的正确性和效率。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值