扩展欧几里得算法

扩展欧几里得算法求的是方程的解。原理如下

 

,当时,,此时,否则设

 

     

 

由于,所以进一步得到

 

     

 

所以得到

 

                   

 

代码:

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;
}


题目: http://poj.org/problem?id=2142

 

题意:有两种类型的砝码质量分别为,要求称出质量为的物品,要求的数量的数量的和

     最小,如果有多个最小值,取最小的。

 

分析:扩展欧几里得求出特解后,把转化为最小正值,即,若

     求出的为负值,则把变正,意思就是砝码放置的位置有左右之分,可以左面的减去右面的,也可以右面

     的减去左面的。同理,再求出为最小合法正值时的解,将这两种情况比较取小的即可。

 

代码:

#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;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值