扩展欧几里得算法求的是方程的解。原理如下
设,当时,,此时,否则设
由于,所以进一步得到
所以得到
代码:
void extend_Euclid(LL a, LL b, LL &x, LL &y) { if(b == 0) { x = 1; y = 0; return; } extend_Euclid(b, a % b, x, y); LL tmp = x; x = y; y = tmp - (a / b) * y; }
题意:有两种类型的砝码质量分别为和,要求称出质量为的物品,要求的数量和的数量的和
最小,如果有多个最小值,取最小的。
分析:扩展欧几里得求出特解后,把转化为最小正值,即,,若
求出的为负值,则把变正,意思就是砝码放置的位置有左右之分,可以左面的减去右面的,也可以右面
的减去左面的。同理,再求出为最小合法正值时的解,将这两种情况比较取小的即可。
代码:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } void extend_Euclid(int a, int b, int &x, int &y) { if(b == 0) { x = 1; y = 0; return; } extend_Euclid(b, a % b, x, y); int tmp = x; x = y; y = tmp - (a / b) * y; } int main() { int a, b, n; while(scanf("%d%d%d",&a,&b,&n)!=EOF) { if(a + b + n == 0) break; int d = gcd(a, b); a /= d; b /= d; n /= d; int x, y; extend_Euclid(a, b, x, y); int tx = x * n; tx = (tx % b + b) % b; int ty = (n - a * tx) / b; if(ty < 0) ty = -ty; y *= n; y = (y % a + a) % a; x = (n - b * y) / a; if(x < 0) x = -x; if(x + y > tx + ty) { x = tx; y = ty; } printf("%d %d\n",x,y); } return 0; }
题目:http://acm.hit.edu.cn/hoj/problem/view?id=2815
题意:给定两个数和,其中,只对和进行加减操作,求最少需要多少步能得到1。
分析:典型的扩展欧几里得算法,注意有些需要特判。
代码:
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> using namespace std; typedef long long LL; LL gcd(LL a,LL b) { return b ? gcd(b,a%b):a; } void extend_Euclid(LL a,LL b,LL &x,LL &y) { if(b == 0) { x = 1; y = 0; return; } extend_Euclid(b,a%b,x,y); LL tmp = x; x = y; y = tmp - (a / b) * y; } int main() { int T; cin>>T; while(T--) { LL a,b; cin>>a>>b; if(a < b) swap(a,b); LL g = gcd(a,b); if(g != 1) { puts("-1"); continue; } if(b == 1 && a == 2) { puts("1"); continue; } if(b == 1) { puts("2"); continue; } if(b == 0 && a == 1) { puts("1"); continue; } LL x,y; extend_Euclid(a,b,x,y); LL ans = abs(x) + abs(y); if(x < 0) { LL tmp = abs(x + b) + abs(y-a); if(tmp < ans) ans = tmp; } else { LL tmp = abs(x - b) + abs(y + a); if(tmp < ans) ans = tmp; } cout<<ans - 1<<endl; } return 0; }