• POJ1061 青蛙的约会


    一、题目

    POJ 1061    青蛙的约会

    【关于“欧几里得求最大公约数”和“扩展欧几里得算法”的题目】

    二、题目源程序

    #include <iostream>
    
    using namespace std;
    
    #define LL long long
    
    LL gcd(LL a, LL b)
    {
        return b ? gcd(b, a%b) : a;
    }
    
    //find x, y that satisfied the equation ax+by=d, which minimize the {|x|+|y|}. ps:d = gcd(a,b).
    void exgcd(LL a, LL b, LL &d, LL &x, LL &y)
    {
        if (!b)
        {
            d = a, x = 1, y = 0;
        }
        else
        {
            exgcd(b, a %b, d, y, x);
            y -= x * (a / b);
        }
    }
    //1、先计算Gcd(a, b),若n不能被Gcd(a, b)整除,则方程无整数解;否则,在方程两边同时除以Gcd(a, b),得到新的不定方程a' * x + b' * y = n',此时Gcd(a', b')=1;
    //2、利用上面所说的欧几里德算法求出方程a' * x + b' * y = 1的一组整数解x0, y0,则n' * x0,n' * y0是方程a' * x + b' * y = n'的一组整数解;
    //3、根据数论中的相关定理,可得方程a' * x + b' * y = n'的所有整数解为:
    //x = n' * x0 + b' * t
    //y = n' * y0 - a' * t
    //(t为整数)
    bool getans(LL a, LL b, LL c, LL &ans)// ax + by = c 最小整数解
    {
        LL r = gcd(a, b), y0;
        if (c%r)//no solutions
        {
            return false;
        }
    
        a /= r; b /= r; c /= r;
    
        exgcd(a, b, r, ans, y0);//至此,上面的说明解决了
    
        LL t = c * ans / b;
        ans = c * ans - t * b;
    
        /*此时方程的所有解为:x = c*ans - b*t, x的最小的可能值是0
        令x = 0可求出当x最小时的t的取值,但由于x = 0是可能的最小取值,实际上可能x根本取不到0
        那么由计算机的取整除法可知:由 t = c*k1 / b算出的t
        代回x = c*ans - b*t中,求出的x可能会小于0,此时令t = t + 1,求出的x必大于0;
        如果代回后x仍是大于等于0的,那么不需要再做修正。*/
    
        if (ans < 0)
        {
            ans += b;
        }
        return true;
    }
    int main()
    {
        LL x, y, m, n, L;
        while (cin >> x >> y >> m >> n >> L)
        {
            LL a = n - m, b = L, c = x - y;
            LL ans;
            bool flag = getans(a, b, c, ans);
            if (!flag)
            {
                cout << "Impossible" << endl;
                continue;
            }
            cout << ans << endl;
        }
    }

    三、解题思路

          两只青蛙跳一次所花费的时间相同,我们设其为t,则x+mt是青蛙A从坐标原点到终点所走的距离,y+nt是B走的距离,要想碰面,则他们相减一定是地面周长的整数倍,设为k*L;则:(x+mt)-(y+nt)=kl;变形得:(m-n)t-(y-x)=kL;即有(m-n)t mod L=y-x;为线性同余方程。此方程有解当且仅当y-x能被m-n和L的最大公约数(记为gcd(m-n,L)),即gcd(m-n,L)|y-x。这时,如果x0是方程的一个解,即当t=x0时,(m-n)t mod L=y-x成立,那么所有的解可以表示为:
    {x0+k(L/gcd(m-n,L))|(k∈整数)}。

    欧几里得算法的拓展应用中有如下三条定理:

       定理一:如果d = gcd(a, b),则必能找到正的或负的整数k和l,使d = a*x+ b*y。

       定理二:若gcd(a, b) = 1,则方程ax ≡ c (mod b)在[0, b-1]上有唯一解。

       定理三:若gcd(a, b) = d,则方程ax ≡ c (mod b)在[0, b/d - 1]上有唯一解。

          证明:上述同余方程等价于ax + by = c,如果有解,两边同除以d,就有a/d * x + b/d * y = c/d,即a/d * x ≡ c/d (mod b/d),显然gcd(a/d, b/d) = 1,所以由定理二知道x在[0, b/d - 1]上有唯一解。所以ax + by = c的x在[0, b/d - 1]上有唯一解,即ax ≡ c (mod b)在[0, b/d - 1]上有唯一解。

          如果得到ax ≡ c (mod b)的某一特解X,那么令r = b/gcd(a, b),可知x在[0, r-1]上有唯一解,所以用x = (X % r + r) % r就可以求出最小非负整数解x了!(X % r可能是负值,此时保持在[-(r-1), 0]内,正值则保持在[0, r-1]内。加上r就保持在[1, 2r - 1]内,所以再模一下r就在[0, r-1]内了)。

    四、心得体会

    起初在运行之后得到的结果正确,我就提交了。可是没有通过。

    原因在哪?

    输入问题!

    起初我的程序里是没有      while (cin >> x >> y >> m >> n >> L)     这句话的,

    我写的是  cin >> x >> y >>m>> n >>  L;     没有while的判断。

    所以题目要求    “输入只包括一行5个整数”    而我在输入过程中即使每行输一个,输5行,也会照常运行,不会跳出。

    注意细节,输入输出!

     

     
  • 相关阅读:
    Caused by: java.lang.IllegalArgumentException: Not an managed type: class XXX
    SpringBoot配置文件详细解析
    解决eclipse环境下maven项目tomcat启动,未加载到项目的问题
    CSS+元素,鼠标事件触发鼠标模形变成手状的形状
    LeetCode-Wildcard Matching
    LeetCode-NQueensII
    LeetCode-Climbing Stairs
    LeetCode-Word Search
    LeetCode-Minimum Window Substring
    LeetCode-Largest Rectangle in Histogram
  • 原文地址:https://www.cnblogs.com/fightfor/p/3860968.html
Copyright © 2020-2023  润新知