狀態轉移思想解讀:輾轉相除(歐幾里德)算法及擴展

原創文章,轉載請註明: 轉載自 SunliyMonkey技術博客
本文鏈接地址: 狀態轉移思想解讀:輾轉相除(歐幾里德)算法及擴展
URL: http://blog.csdn.net/sunliymonkey/article/details/48102067

1 算法實現

1.1 歐幾里德算法(輾轉相除法)

歐幾里德算法,也被稱爲輾轉相除法,其被用於求解兩個數之間的最大公約數,常用gcd(AB) 進行表示。

它的算法實現十分容易,如下:

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

1.2 擴展歐幾里德算法

擴展歐幾里德算法是用來求解這樣一個式子:

        Ax+By=gcd(AB)
        求解: x=? , y=?
這裏的x,y不是唯一解,當得知一組可行解之後,其它的可行解都可以表示出來:
       
        xk=x+(kBgcd(A,B))
        yk=y(kAgcd(A,B))
        k 爲任意整數             

在這裏不闡述,x,y的值有何用處,如果你是acmer,應該發現有不少題,需要利用這個性質。

擴展歐幾里德算法的實現也很簡單,在原有歐幾里德算法的基礎上,少許額外的代碼,即能實現:

    int exGcd(int a,int b,int &x,int &y)  
    {  
        if(b==0)  
        {  
            x = 1;  
            y = 0;  
            return a;
            // 此時a = gcd(A,B)  
            // a * 1 + b * 0 = gcd(A,B)
            // 由於b=0,y可以任意取值
        }  

        int d = exGcd(b, a%b, y, x); // 注意這裏x,y的位置對調  
        y -= a/b * x;  
        return d; // 返回最大公約數  
    }  

2 狀態轉移思想

看了上面的實現,相信你的第一感覺是十分簡潔,確實也如此,對於一個不懂這兩種算法的人,如果提醒你從“動態規劃”,“狀態轉移”等角度思考這兩個問題,相信會有不少人能夠AC它們。

先來看看兩個明顯的結論:

  • A=Bgcd(A,B)=AB

  • A=0gcd(A,B)=BB=0gcd(AB)=A

看到這裏,相信你會有一種直覺:是否能夠將求解gcd(A,B) , 轉換成更小的兩個數A1,B1 ,使得gcd(A,B)=gcd(A1,B1) 呢?而這種狀態轉移思想經常被用到:

  • 分治: 大問題分解成小問題,小問題更容易被解決,最終,合併小問題的結果,解決大問題

  • 動態規劃: 一個狀態能夠從多個狀態轉移而來,其最優值將從這多個狀態的最優值中選取


3 狀態轉移方程

3.1 歐幾里德

結論: gcd(A,B)=gcd(AB,B)

證明:

 設 A=k1gcd(A,B),B=k2gcd(A,B)(AB)

 顯然 gcd(k1,k2)=1

 AB=(k1k2)gcd(A,B)

 可以使用反證法證明: gcd(k1k2k2)=1
 因此gcd(A,B)=gcd(AB,B)

 當你發現存在這樣的狀態轉移,歐幾里得算法,其實已經解決了。然後再分析下,不難發現更快速的狀態轉移方程:

     gcd(A,B)=gcd(A%B,B)

 而這就是上面代碼實現中,使用的狀態轉移方程。


3.2 擴展歐幾里德

有了上面狀態轉移的基礎,我們可以將問題進行如下轉換:
狀態轉移:(A0,B0,x0,y0)(A1,B1,x1,y1)

     A0x0+B0y0=gcd(A,B)
     A1x1+B1y1=gcd(A,B)

其中:
 A1=B0
 B1=A0%B0=A0(A0/B0)B0
 x1, y1 的值已經知道,現在需要反推出x0, y0 的值

只需代入上面的關係,即可推導出狀態轉移的公式:

  A1x1+B1y1

 =B0x1+[A0(A0/B0)B0]y1

 =A0y1+B0[x1(A0/B0)y1]

 =A0x0+B0y0

推導結果:

 x0=y1
 y0=x1(A0/B0)y1

擴展歐幾里德算法,就這樣被你解決了!

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