题意
平面上有((0,0))到((n,m))总共((n+1)*(m+1))个格点。任取两点((x,y),(x',y'))连成线段,若线段上没有其他格点,则称这条线段为一条合法边。求((0,0))到((n,m))的最短路径,要求相邻两条边的斜率不能相等。
推导
首先考虑线段上有其他格点的情况,由于两边之和大于第三边,线段数为(k)的路径一定比线段数为(k-1)的路径长。然后,对于边数为2的路径ABC,若AB上存在格点D,则路径ADC一定小于路径ABC。所以最终线段ABC上一定无格点。所以对于(n,m)不互质的情况,最短路径边数一定为2。
对于边数为2的所有路径ABC,若存在点D在三角形ABC内部,则路径ADC一定小于路径A-B-C。所以对于每个横坐标(i),取最接近线段((0,0)-(n,m))的两个(j)作为中间点进行比较即可。
代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int maxn=1e5+5;
double dist(ll n,ll m){
return sqrt(n*n+m*m);
}
void solve(){
ll n,m;
scanf("%lld%lld",&n,&m);
if(__gcd(n,m)==1)
printf("%.15lf
",dist(n,m));
else
{
double ans=n+m;
for(ll i=0;i<=n;i++)
{
ll j1=m*i/n,j2=j1+1;
if(i*m==j1*n)j1--;
j1=max(j1,0ll);
j2=min(j2,m);
if((j1-0)*(n-i)!=(m-j1)*(i-0) && __gcd(i,j1)==1 && __gcd(n-i,m-j1)==1)
ans=min(ans,dist(i,j1)+dist(n-i,m-j1));
if((j2-0)*(n-i)!=(m-j2)*(i-0) && __gcd(i,j2)==1 && __gcd(n-i,m-j2)==1)
ans=min(ans,dist(i,j2)+dist(n-i,m-j2));
}
printf("%.15lf
",ans);
}
}
int main()
{
// ios::sync_with_stdio(false);
int t=1;
scanf("%d",&t);
while(t--)
solve();
return 0;
}