C - One Person Game ZOJ - 3593(拓展欧几里得)

首先要把欧几里得弄清楚,要不很难弄的·········
ax + by = c;
计算出的为 ax + by = gcd(a,b);
r = gcd(a,b)
所以要求真正的x,y则需要乘上 c/gcd(a,b);
然后x,y求的是其中一组解
它的一系列解为 X = x + bt;
Y = y - at;
a = a/r,b = b/r; 这样得出的x,y的解更多,更全面
然后··············
说题意吧···········
题意为可以走长度a,b,a+b 三种长度,求由A到B的最小步数
其实就是求ax + by = (B- A)因为(a + b)可以分解
所以就是找一组xy的值
当xy为同号时就是找x,y的最大值
当xy异号时即为|x| + |y|的值
那么最短路径就是x等于y的时候步数最少
在条线的交点附近
代码如下

#include
#include
#include
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll r = exgcd(b,a%b,x,y);
    ll t = x;
    x = y;
    y = t - a/b*y;
    return r;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll A,B,C,a,b;
        cin>>A>>B>>a>>b;
        ll x,y;
        ll r;
        r = exgcd(a,b,x,y);
        C = B - A;
        if(C%r)
            cout<<"-1"<<'\n';
        else
        {
            x = x*(C/r);
            y = y*(C/r);
            a = a/r;
            b = b/r;
            ll ans = inf*inf,tmp;
            ll mid = (y - x)/(a + b);//两条直线交点的x坐标
            for(ll T = mid - 1; T <= (mid + 1); T++)
            {
                if((x + b*T)*(y - a*T) >=0)
                {
                    tmp = max(abs(x + b*T),abs(y - a*T));
                }
                else
                    tmp = abs(x - y + (a + b)*T);
                ans = min(ans,tmp);
            }
            cout<<ans<<'\n';
        }
    }
    return 0;
}

你可能感兴趣的:(数学,欧几里得)