1 条题解

  • 0
    @ 2025-5-22 13:38:59

    乡村公路问题题解

    题目分析

    问题描述:给定N×NN×N的村庄(每个庄园为100100米×100100米的正方形),计算连接(0,W)(0, W)(100N,E)(100N, E)的直线穿过的庄园数量。若直线与庄园边缘相交,也视为穿过。

    输入格式:多组测试用例,每组输入NN(村庄边长,1N1001≤N≤100)、WW(西侧交点纵坐标)、EE(东侧交点纵坐标)。

    输出格式:每组用例输出被穿过的庄园数量。

    核心难点:如何判断直线穿过的正方形庄园数量,需处理直线与网格边界的相交情况(包括顶点和边缘)。

    算法思路

    核心数学模型

    直线穿越网格的庄园数可通过以下公式计算:

    • 设直线在xx方向跨越dx=Ndx=N个网格(从x=0x=0x=100Nx=100N,共NN个完整网格)。
    • 直线在yy方向的变化量为dy=WEdy=|W-E|,转换为网格单位为k=dy/100k=dy/100(向下取整?不,需精确计算)。
    • 关键公式:穿越数 = dx + dy' - gcd(dx, dy'),其中dx=Ndx=Ndydy'yy方向跨越的网格数,gcdgcd为最大公约数。

    推导过程

    1. 坐标转换:将实际坐标转换为网格单位。每个庄园对应坐标区间为[x×100,(x+1)×100]×[y×100,(y+1)×100][x×100, (x+1)×100]×[y×100, (y+1)×100],其中x,y[0,N1]x,y∈[0, N-1]
    2. 直线方程:设直线方程为y=kx+by=kx+b,由两点(0,W)(0, W)(100N,E)(100N, E)得斜率k=(EW)/(100N)k=(E-W)/(100N),截距b=Wb=W
    3. 跨越次数计算
      • 水平跨越次数:直线在xx方向每穿过一个垂直网格线(x=100mx=100m)时,可能进入新庄园,共NN次(xx00100N100N跨越NN个网格)。
      • 垂直跨越次数:直线在yy方向每穿过一个水平网格线(y=100ny=100n)时,可能进入新庄园,次数为dy=WE/100dy'=|W-E|/100的整数部分?不,需精确到网格单位的变化量。
      • 修正项:当直线同时穿过垂直和水平网格线(即顶点)时,会重复计数,需用gcd(N,dy的整数部分)gcd(N, dy'的整数部分)修正。

    关键公式推导

    设直线在xx方向移动100N100N米时,yy方向变化量为Δy=EW\Delta y=|E-W|。将Δy\Delta y转换为网格单位的变化量m=Δy/100m=\Delta y/100,则:

    • 穿越数 = N+mgcd(N,m的整数部分)N + m - gcd(N, m的整数部分)
      注意:此处mm需为整数吗?实际应取Δy\Delta y的绝对值,且mm可能为小数,但需用数学方法处理。

    代码解析

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    // 计算最大公约数
    int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    
    int main() {
        int N, W, E;
        while (scanf("%d %d %d", &N, &W, &E) != EOF) {
            int dx = N;                          // x方向跨越的网格数
            int dy = abs(E - W);                 // y方向变化量(单位:米)
            int g = gcd(dx, dy);                 // 计算最大公约数
            int count = dx + dy / 100 - g;        // 穿越数公式
            printf("%d\n", count);
        }
        return 0;
    }
    

    代码解释

    1. 输入处理:读取NNWWEE
    2. 计算变化量dx=Ndx=Nxx方向网格数),dy=EWdy=|E-W|yy方向实际距离变化)。
    3. 最大公约数:用gcd(dx,dy)gcd(dx, dy)计算修正项,避免顶点处重复计数。
    4. 穿越数公式count=dx+dy/100gcd(dx,dy/100)count = dx + dy/100 - gcd(dx, dy/100),其中dy/100dy/100yy方向跨越的网格数。

    示例分析

    输入样例33 150150 5050

    • N=3N=3W=150W=150E=50E=50,则dy=50150=100dy=|50-150|=100
    • dx=3dx=3dy/100=1dy/100=1gcd(3,1)=1gcd(3,1)=1
    • 穿越数=3+11=4=3+1-1=4,与输出一致。

    关键点

    1. 网格穿越模型:直线穿越网格的庄园数等于横向跨越次数加纵向跨越次数,减去同时跨越的次数(由gcdgcd计算)。
    2. 单位转换:将yy方向的实际距离变化(米)转换为网格单位(每100100米一个网格)。
    3. 边界处理
      • W=EW=E时,直线水平,dy=0dy=0,穿越数=N+00=N=N+0-0=N
      • 当直线经过网格顶点时,gcdgcd不为00,修正项起作用,避免重复计数。

    复杂度分析

    • 时间复杂度O(1)O(1) per test case,仅涉及基本运算和gcdgcd计算(时间复杂度可视为常数)。
    • 空间复杂度O(1)O(1),仅存储若干整数变量。

    总结

    本题通过数学建模将网格穿越问题转化为数值计算,利用最大公约数处理边界相交情况,高效解决了庄园数量的计算问题。关键在于理解直线穿越网格的数学规律,避免枚举所有庄园,从而实现O(1)O(1)的时间复杂度。

    • 1

    信息

    ID
    649
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    1
    已通过
    1
    上传者