extendGcd,即擴充套件歐幾里得演算法的C++模板化解釋
阿新 • • 發佈:2019-02-11
剛剛接觸感覺很高大上的“擴充套件歐幾里得演算法“,很鬱悶,研究了很久。現在感覺能夠套模板了,當然這樣是遠遠不夠的,不過先寫篇部落格記錄一下最近的動態。幫助自己記憶,也可以幫助大家理解下這個數學演算法,當然歡迎各位的斧正和指點,我將不斷努力!
首先,明確我們要求ax+by=c中x,y的整數解(至於沒有解的情況下邊會討論)
大家應該看到過ax+by=Gcd(a,b)的式子,現在我也不明白這是什麼,以下是我大概能夠死記硬背的(大家能學會的還是去學學原理)。
先求gcd(a,b),程式如下:
LL d=gcd(a,b);typedef long long LL; using namespace std; LL gcd(LL a,LL b){ while(a%b){ LL temp=b; b=a%b; a=temp; } return b; }
後,a/=d,b/=d,c/=d;這裡有當c%d!=0是,ax+by=c不存在整數解(我也不知道為什麼,真的模板化了)
於是原式變成a'x+b'y=c'。據說那個擴充套件歐幾里得求的是a'x+b'y=1的解,給出extendGcd(a,b)的模板
這裡不難得到修改後的x,y為方程a'x+b'y=1的解,那麼c'x0,c'y0就是a'x+b'y=c'的一組特解了,根據引數方程的性質,我們引入t(整數)來寫出x,y通解的引數方程x=c'x0-b't,y=c'y0+a't。void exGcd(LL a,LL b,LL &x,LL &y){ if(b==0){ x=1;y=0; return ; } exGcd(b,a%b,x,y); LL temp; temp=y; y=x-a/b*y; x=temp; }
通常題目要求我們求問題的最小解,所以當x->0時,我們求出的t=c'x0/b(這裡是有誤差的,因為在C語言中的除不一定,事實上,我們可以判斷下x<0時,可以讓t=t+1。
下面來看一道典型的模板題吧。
poj 1061
青蛙的約會Time Limit: 1000MS | Memory Limit: 10000K |
Total Submissions: 96453 | Accepted: 18021 |
Description
兩隻青蛙在網上相識了,它們聊得很開心,於是覺得很有必要見一面。它們很高興地發現它們住在同一條緯度線上,於是它們約定各自朝西跳,直到碰面為止。可是它們出發之前忘記了一件很重要的事情,既沒有問清楚對方的特徵,也沒有約定見面的具體位置。不過青蛙們都是很樂觀的,它們覺得只要一直朝著某個方向跳下去,總能碰到對方的。但是除非這兩隻青蛙在同一時間跳到同一點上,不然是永遠都不可能碰面的。為了幫助這兩隻樂觀的青蛙,你被要求寫一個程式來判斷這兩隻青蛙是否能夠碰面,會在什麼時候碰面。我們把這兩隻青蛙分別叫做青蛙A和青蛙B,並且規定緯度線上東經0度處為原點,由東往西為正方向,單位長度1米,這樣我們就得到了一條首尾相接的數軸。設青蛙A的出發點座標是x,青蛙B的出發點座標是y。青蛙A一次能跳m米,青蛙B一次能跳n米,兩隻青蛙跳一次所花費的時間相同。緯度線總長L米。現在要你求出它們跳了幾次以後才會碰面。
Input
輸入只包括一行5個整數x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。Output
輸出碰面所需要的跳躍次數,如果永遠不可能碰面則輸出一行"Impossible"Sample Input
1 2 3 4 5
Sample Output
4
程式碼如下
#include <iostream>
#include <cstdio>
typedef long long LL;
using namespace std;
LL gcd(LL a,LL b){
while(a%b){
LL temp=b;
b=a%b;
a=temp;
}
return b;
}
void exGcd(LL a,LL b,LL &x,LL &y){
if(b==0){
x=1;y=0;
return ;
}
exGcd(b,a%b,x,y);
LL temp;
temp=y;
y=x-a/b*y;
x=temp;
}
int main()
{
LL x,y,m,n,l,ans,key,t;
while(~scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&l)){
/* (n-m)*ans+k*l=x-y;
* n-m=a,ans=x,k=y,l=b,x-y=c;
* a*x+b*y=c;
*/
LL a=n-m,b=l,c=x-y;
LL d=gcd(a,b);
//cout << d <<endl;
if(c%d) {printf("Impossible\n");continue;}
a/=d;b/=d;c/=d;
exGcd(a,b,ans,key);
t=c*ans/b;
ans=c*ans-t*b;
if(ans<0)
ans+=b;
printf("%I64d\n",ans);
}
return 0;
}
學不好的我..只好這樣背公式了,希望以後能學好!