關於擴展歐幾里得定理
衆所周知,擴展歐幾里得定理是用來求形如(a,b,c皆爲整數)這樣的方程的一組解[注,僅是一組解]的定理
它的原理比較複雜,本人學了挺久才懂了一點,這裏就不談了,擴歐的核心是它的思想,它的思想可以用來解決許多題
該方程有解的條件 :
要使(a,b,c皆爲整數) 有解,我們設k=gcd(a,b),可以將原方程寫成的形式
a,b,b均爲整數
k|c 即 gcd(a,b)|c // k|c數學裏爲 c%k=0
由此可見,該方程有解的條件爲c%gcd(a,b)=0
求解方法 :
由於是求解的一組解,在方程有解的條件下,我們可以考慮先求出的一組解,
爲什麼這樣考慮呢,這樣子變化有什麼好處呢?當我們將原方程轉變爲這樣的方程之後,實際上我們求出的x與y並不是
原方程的解,我們可以理解爲轉變後的方程的解爲x'與y',實際上該方程是將原方程除以
c/gcd(a,b)後所得到的,所以原方程的解爲那麼我們先求出
原方程的解便只需乘以c/gcd(a,b)就能得到了
另外說明,c=gcd(a,b)是原方程有解的最小情況,利用這個性質,裴蜀定理也就不難寫出來了
那麼該如何求解呢?
衆所周知(又是這個詞,詞窮) gcd的寫法return b==0?a:gcd(b,a%b);(爲了節約篇幅強行壓縮)關鍵的一步就是
gcd(a,b)==gcd(b,a%b)了,這個的成立性就不證明了,我們求解是需要利用到gcd的這個特性的
我們可以得到這樣一個方程(這裏的%顯示不出來就用mod代替了),然後我們將gcd(b,a%b)中的b和a代入原方程
那麼可以得到gcd(b,a%b) = bx+(a%b)y,注意,此時的x與y也不是原方程的解,也可以理解爲x',y'這樣子我們就可以得到
(這裏是將gcd(a,b)的a,b反代入原方程),又因爲電腦中的取模運算a%b是等價於a-a/b*b的
所以我們又可以將最後一個方程變成bx'+(a-a/b*b)y',然後與第一個方程放在一起便有
,然後拆項移項,變成,最後便能得出這樣的轉移方程
,有了這樣的轉移方程,那麼我們可以遞歸地寫出代碼了,遞歸結束條件就是b==0時,此時的方程
ax+by=gcd(a,b),b==0,所以就是ax=a,那麼x=1,y=0
//已知a,b 求解 ax+by=1
void ex_gcd (int a,int b,int &x,int &y)
{
if (b==0){x=1,y=0;return;}
ex_gcd(b,a%b,x,y);
int tmp=x;
x=y,y=tmp-a/by;
}
/*
* 若求解 ax+by=c
* △條件(是否有解) : 滿足gcd(a,b)|c [c%gcd(a,b)==0]
* 可以先求 ax+by=gcd(a,b)
* 再將求得的x與y分別乘以c/gcd(a,b)
*/
那麼擴展歐幾里得便講完了,下面說一下上文提到的裴蜀定理
裴蜀定理
題目描述
給出n個數(A1...An)現求一組整數序列(X1...Xn)使得S=A1X1+...AnXn>0,且S的值最小
輸入輸出格式
輸入格式:
第一行給出數字N,代表有N個數 下面一行給出N個數
輸出格式:
S的最小值
我們可以將A1X1+A2X2+...+AnXn看成許多個ax+by,那麼我們要求的便是c的最小值,上文說過,c的最小值就是gcd(a,b),所以我們只需求出所有的gcd便可
附上代碼
#include <cstdio>
#include <cmath>
using namespace std;
int ans,n,t;
int gcd (int a,int b)
{
return !b?a:gcd(b,a%b);
}
int main ()
{
scanf("%d",&n);
scanf("%d",&ans);//ans初始賦值爲第一個數
while (--n){
scanf("%d",&t);
t=abs(t);
ans=abs(gcd(ans,t));
}
printf("%d",ans);
return 0;
}
注,如若有誤或者哪裏講得不清楚,請聯繫本人更改或者在下方留言,謝謝啦~\(≧▽≦)/~