Traveling in the Grid World 暴力+数学

题目大意:

开始位于\((0,0)\),最后要到达 \((n,m)\) ,如果你要从 \((sx,sy)\) 走到 \((gx,gy)\) 那么连接起点和终点,连线不能穿过任意的网格点,这样的一条连线被称为一条路径,要求不能存在任意两条路的斜率相同,问从起点走到终点的最短路径是多少。

题解:

这个题目首先要明白,如果 \(gcd(a,b)==1\) 那么从 \((0,0)\)\((a,b)\) 则没有穿过任意一个网格点,明白这个之后就是一个暴力,暴力枚举起点到终点的连线上的所有点的上下点,以这个点作为中点,判断这个点到起点和终点 \(gcd\) 是否相同,斜率是否不相同,如果满足这些条件,那么求出两段的距离,对答案取 \(min\)

难度其实不大,因为推出 \(gcd(a,b)==1\) ,则表示 \((0,0)\)\((a,b)\) 没有穿过任意一个网格点,这个不是很难,难点在于想到暴力枚举吧,这个是我没有想到的。。。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 4e5+10;
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int n,m;
double solve(int i,int y) {
    if (gcd(i, y) == 1 && gcd(n - i, m - y) == 1 && 1ll * i * (m - y) != 1ll * (n - i) * y) {
        return sqrt(1.0 * i * i + 1.0 * y * y) + sqrt(1.0 * (n - i) * (n - i) + 1.0 * (m - y) * (m - y));
    }
    return 1e9;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        double ans = 1e9;
        if(gcd(n,m)==1) ans = sqrt(1.0*n*n+1.0*m*m);
        else{
            for(int i=1;i<n;i++){
                int y = i*m/n;
                ans = min(ans,solve(i,y));
                ans = min(ans,solve(i,y+1));
                ans = min(ans,solve(i,y-1));
            }
        }
        printf("%.10f\n",ans);
    }
    return 0;
}