擴展歐幾里得算法...... POJ 1061

 此題其實就是擴展歐幾里得算法-求解不定方程,線性同餘方程。

  設過s步後兩青蛙相遇,則必滿足以下等式:

    (x+m*s)-(y+n*s)=k*l(k=0,1,2....)

  稍微變一下形得:

    (n-m)*s+k*l=x-y

    令n-m=a,k=b,x-y=c,即

    a*s+b*l=c

  只要上式存在整數解,則兩青蛙能相遇,否則不能。

  首先想到的一個方法是用兩次for循環來枚舉s,l的值,看是否存在s,l的整數解,若存在則輸入最小的s,

但顯然這種方法是不可取的,誰也不知道最小的s是多大,如果最小的s很大的話,超時是明顯的。

  其實這題用歐幾里德擴展原理可以很快的解決,先來看下什麼是歐幾里德擴展原理:

  歐幾里德算法又稱輾轉相除法,用於計算兩個整數a,b的最大公約數。其計算原理依賴於下面的定理:

  定理:gcd(a,b) = gcd(b,a mod b)

  證明:a可以表示成a = kb + r,則r = a mod b

  假設d是a,b的一個公約數,則有

  d|a, d|b,而r = a - kb,因此d|r

  因此d是(b,a mod b)的公約數

  假設d 是(b,a mod b)的公約數,則

  d | b , d |r ,但是a = kb +r

  因此d也是(a,b)的公約數

  因此(a,b)和(b,a mod b)的公約數是一樣的,其最大公約數也必然相等,得證

  歐幾里德算法就是根據這個原理來做的,其算法用C++語言描述爲: 

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

  當然你也可以寫成迭代形式:

  int Gcd(int a, int b)
  {
      while(b != 0)
      {
          int r = b;
          b = a % b;
          a = r;
      }
      return a;
  }

  本質上都是用的上面那個原理。

  補充: 擴展歐幾里德算法是用來在已知a, b求解一組x,y使得a*x+b*y=Gcd(a,b)(解一定存在,根據數論中的相關定理)。擴展歐幾里德常用在求解模線性方程及方程組中。下面是一個使

用C++的實現:

  int exGcd(int a, int b, int &x, int &y)
  {
      if(b == 0)
      {
          x = 1;
          y = 0;
          return a;
      }
      int r = exGcd(b, a % b, x, y);
      int t = x;
      x = y;
      y = t - a / b * y;
      return r;
  }

  把這個實現和Gcd的遞歸實現相比,發現多了下面的x,y賦值過程,這就是擴展歐幾里德算法的精髓。

  可以這樣思考:

  對於a' = b, b' = a % b 而言,我們求得 x, y使得 a'x + b'y = Gcd(a', b')

  由於b' = a % b = a - a / b * b (注:這裏的/是程序設計語言中的除法)

  那麼可以得到:

  a'x + b'y = Gcd(a', b') ===>
  bx + (a - a / b * b)y = Gcd(a', b') = Gcd(a, b) ===>
  ay +b(x - a / b*y) = Gcd(a, b)

  因此對於a和b而言,他們的相對應的p,q分別是 y和(x-a/b*y).

  在網上看了很多關於不定方程方程求解的問題,可都沒有說全,都只說了一部分,看了好多之後才真正弄清楚不定方程的求解全過程,步驟如下:

  求a * x + b * y = n的整數解。

  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爲整數)

    上面的解也就是a * x + b * y = n 的全部整數解。

 

 

 

 

 

步驟如下:
擴展歐幾里德算法-求解不定方程,線性同餘方程:
解不定方程ax  +  by  =  n的步驟如下:  
 
(1)計算gcd(a,  b).  若gcd(a,  b)不能整除n,則方程無整數解;否則,在方程的兩邊同除以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)根據&@^%W#&定理,可得方程a'x  +  b'y  =  n'的所有整數解爲:  
    x  =  n'x0  +  b't  
    y  =  n'y0  -  a't  
   (t爲整數)  
這也就是方程ax  +  by  =  n的所有整數解  
 
利用擴展的歐幾里德算法,計算gcd(a,  b)和滿足d  =  gcd(a,  b)  =  ax0  +  by0的x0和y0,
也就是求出了滿足a'x0  +  b'y0  =  1的一組整數解。因此可得:  
x  =  n/d  *  x0  +  b/d  *  t  
y  =  n/d  *  y0  -  a/d  *  t  
(t是整數)   
 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章