扩展欧几里得算法求的是方程的解。原理如下
设,当时,,此时,否则设
由于,所以进一步得到
所以得到
代码:
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;
}