HIT2815Min Chain扩展欧几里德

来源:互联网 发布:人工智能导论教学大纲 编辑:程序博客网 时间:2024/05/16 10:50

题目:http://acm.hit.edu.cn/hoj/problem/view?id=2815

 

题意:给定两个数,其中,只对进行加减操作,求最少需要多少步能得到1

 

分析:典型的扩展欧几里得算法,注意有些需要特判。


小结:

看到一篇博客说 : a*x+b*y==gcd(a,b)成立的式子的特解:x1,y1,满足:x=x1+t*b,y=y1+t*b,且|x1|<b,|y1|<a

因为题目要求的是|x1|+|y1|最小,故此:当x1<0时比较|x1+b|+|y1-a|和x1,y1 的大小取小的,当x1>0时,比较|x1-b|+|y1+a|和x1,y1 的大小取小的。

对于上面的|x1|<b,|y1|<a这个结论,我也不知道到底是对还是错,网上的题解几乎都采用了这种意思的做法。感觉上貌似是对的,但是也不知道怎么证明。


如果希望更保险的做法的话,还是用手动将x转化为正的最小,转化y时也一样:

#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)        {            x = (x%b + b) % b;            LL ty = (1-a*x) / b;            if(ty < 0)                ty = -ty;            LL tmp = x + ty;            if(tmp < ans) ans = tmp;        }        else        {            y = (y%a + a) % a;            LL tx = (1-b*y) / a;            if(tx < 0)                tx = -tx;            LL tmp = y + tx;            if(tmp < ans) ans = tmp;        }        cout<<ans - 1<<endl;    }    return 0;}



网上类似于结论性的写法:

#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>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(a == 2 && b == 1)        {            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;}


0 0
原创粉丝点击