zoukankan      html  css  js  c++  java
  • POJ 1061 扩张欧几里得问题

    题目大意:

      有两只青蛙A和B,住在同一纬线上。它们分别从坐标x和y出出发。青蛙A每次能跳跃m米,青蛙B每次能跳跃n米,A和B每次都在同一之间跳跃。设地球的纬线长度为L。

      问A和B是否能够相遇(在同一时间到达同一坐标),如果能够相遇,那么需要跳跃多少次?

    解题思路:

      利用欧几里得扩展式子。

      我们这道题最后是要求x + k*m = y + k*n + pL。其中k、p为整数,需要确定。

      将上面的等式进行简单的变换,可得 

      (x-y) = k(n-m) + pL

      设a=n-m,b = L,c=x-y,则上面的等式变为:

      a*k + b*p = c

      在介绍上面等式的解法之前,我们先介绍利用欧几里得的方法求解最大公约数。

      在我们求解最大公约数的时候,我们用到了欧几里得方法,主要是以下的递归式:

      gcd(a, b) = gcd(b, a%b)。

      参考《算法导论》上数论的那一章,我们现在对其进行证明。

      要证明gcd(a, b) = gcd(b, a%b)。只需要证明gcd(a, b) | gcd(b, a%b) && gcd(b, a%b)|gcd(a, b)。

      a%b可以用a,b线性表示。a % b = a - floor(a/b)*b。floor()表示向下取整。

      设d = gcd(a, b),因为a%b是a和b的线性组合,所以可得d|(a%b)。

      又因为d|b。所以可得d|gcd(b, a%b)。即gcd(a, b) | gcd(b, a%b)。

      证明gcd(b, a%b)|gcd(a, b)的过程与上面的类似,这里就不在叙述了。

      有了上面的递推式,求解最大公约数的程序可以如下这样写:

    int gcd(int a, int b)
    {
        if (b == 0)
            return a;
        else
            return gcd(b, a%b);
    }

      

      为了求解上面的式子:a*k + b*p = c,我们先求解如下的式子

      a*k + b*p = d,其中d = gcd(a, b)。

      考虑下面的式子:

      d = a*k + b*p = b*k` + (a%b)*p`

      又因为a%b =  a - floor(a/b)*b

      所以,d = b*k` + (a - floor(a/b)*b)*p` = a*p` + b*(k` - floor(a/b)*p`) = a*k + b*p。

      所以可得 k = p`; p = k`-floor(a/b)&p`。

      

      于是扩展的欧几里得代码可以写成如下: 

    int extendedEuclid(int a, int b, int &k, int &p)
    {
        if (b == 0) {
            k = a;
            y = 1;
            return;
        }
    
        extendedEuclid(b, a%b, k, p);
        int temp = k;
        k = p;
        p = (temp - a/b)*p;
    }

      在求出a*k + b*p = d的解k后,在等式两边同时乘以c/d。得到 k = k*c/d, 即得到a*k + b*p = c的一个解。

      然后再计算k = (k%b + b)%b。即得到原问题的一个解。

      最后AC的代码如下(需要注意的是这道题的数的范围可能会超出整数,因此要使用long long类型):

      Memory: 132KTime: 0MS

      Language: C++Result: Accepted

    #include <stdio.h>
    #include <stdlib.h>
    #include <memory.h>
    #include <string>
    #include <iostream>
    #include <stack>
    using namespace std;
    
    typedef long long LL;
    
    
    int gcd(LL a, LL b)
    {
        if (b == 0)
            return a;
        else
            return gcd(b, a%b);
    }
    
    void extendedEuclid(LL a, LL b, LL &x, LL &y)
    {
        if (b == 0) {
            x = a;
            y = 1;
            return;
        }
    
        extendedEuclid(b, a%b, x, y);
        LL temp = x;
        x = y;
        y = temp - (a/b)*y;
    }
    
    int main(int argc, const char *argv[])
    {
        //freopen("in.txt", "r", stdin);
    
        LL x, y, m, n, L;
        LL a, b, c;
        LL k , j, d;
    
        scanf("%lld %lld %lld %lld %lld", &x, &y, &m, &n, &L);
    
        // a*k + b * j = d
        a = n - m;
        b = L;
        c = x - y;
        if (a < 0) {
            a = -a;
            c = -c;
        }
    
        int r = gcd(a, b);
        if (c % r != 0) {
            printf("Impossible\n");
        }
        else {
            a = a / r;
            b = b / r;
            c = c / r;
            extendedEuclid(a, b, k, j);
            k = ((k*c)%b + b)%b;
            printf("%lld\n", k);
        }
    
        return 0;
    }

    POJ上与此题类似的题目还有POJ2115POJ2142,有兴趣可以一起刷了.

  • 相关阅读:
    不舍
    java 笔记
    Javascript 行为委托
    JavaScript 函数调用的 this词法
    Javascript 闭包
    Javascript 原型链
    理解css的BFC
    多模态检索之CCA算法
    MySQL 基础概念、基础配置、密码破解
    Python的进程和线程
  • 原文地址:https://www.cnblogs.com/lovesaber/p/2762588.html
Copyright © 2011-2022 走看看