Loading

gym102900L Traveling in the Grid World (2020 ICPC Shanghai Site)

题意

平面上有\((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\n",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\n",ans);
    }
}

int main()
{
    // ios::sync_with_stdio(false);
    int t=1;
    scanf("%d",&t);
    while(t--)
        solve();

    return 0;
}
posted @ 2020-12-19 22:10  intmian  阅读(219)  评论(0编辑  收藏  举报