题目大意

  • 给定源点 和目标点
  • 定义点的移动方式
  • 数据范围:

问:源点经过任意次位移,是否有可能到达目标点?

分析

  • 从数据范围来看,显然是不允许暴力搜索求解的。因此,这是一道巧妙的数学题(或者脑筋急转弯)。
  • 两点都位于第一象限, 均为正整数,因此可以排除所有 的情况。
  • 根据移动方式可知,将 中的较大值对对方取模,即可退回上个状态 。(这里思路不是很严谨)

求解

递归搜索的思路很简单,但会因为递归次数过多而栈溢出或因为搜索空间过大而超时。

bool reachingPoints(int sx, int sy, int tx, int ty) {
    if (sx > tx || sy > ty)
        return false;
    if (sx == tx && sy == ty)
        return true;
    return reachingPoints(sx + sy, sy, tx, ty) || reachingPoints(sx, sx + sy, tx, ty);
}

根据点的状态转移关系,我们可以将目标点尽量逼近源点,然后只需对剩下一个轴坐标做判断即可。

bool reachingPoints(int sx, int sy, int tx, int ty) {
    if (sx > tx || sy > ty)
        return false;
 
    while (sx < tx && sy < ty) {
        if (tx < ty)
            ty %= tx;
        else
            tx %= ty;
    }
                                                        
    // 每次循环只进行一次操作,因此循环结束时分两种情况
    // 1. sx == tx:由于两点 x 不变,合法解只存在 ty = sy + n * sx
    // 2. sy == ty:由于两点 y 不变,合法解只存在 tx = sx + n * sy
    return (sx == tx && (ty - sy) % sx == 0) || (sy == ty && (tx - sx) % sy == 0);
}