poj2142:The Balance(扩展欧几里德)

题目

poj2142
已知 a b c ,求最小的 | x | + | y | 使 a x + b y = c 成立的


题解

可以通过扩展欧几里德求出一组解 x 0 y 0
那么通解就是 { x = x 0 + b d × t y = y 0 a d × t t 为系数, d = g c d ( a , b )
| x | + | y | 最小值…依靠 经验 咳 感觉 咳咳 画图..得知最小值应当在交点附近(因为题里要求是正数嘛~)
咳 题里还说要求 | x | + | y | 最小的同时 a × | x | + b × | y | 最小 (我不会说我没看见这个条件..wa了半天..然后对着网上的程序好奇了半天)
这就姑且算作第一种方法吧…

感觉下面这个..好理解【捂脸】
第二种~
由题,只有两种可能: a x 1 b y 1 = c x 1 > 0 或者 b y 2 a y 2 = c y 2 > 0
通过扩展欧几里德我们能求出一组通解( x 0 y 0
x 1 y 2 为最小自然数,然后便可以求出 y 1 x 2
再比较一下大小就可以了


代码

//方法一
#include <cstdio>
#include <algorithm>
using namespace std;
#define inf 0x7fffffff
int exgcd(int a,int b,int &x,int &y){
    if(!b){x=1,y=0;return a;}
    int c=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return c; 
}
int main(){
    freopen("poj2142.in","r",stdin);
    int a,b,c,x,y;
    while(scanf("%d%d%d",&a,&b,&c)>0 && (a||b||c)){
        int d=exgcd(a,b,x,y),t=c/d;
        x*=t,y*=t;
        int t1=-x*d/b,t2=y*d/a,ans=inf,x0,y0;
        for(int i=t1-1;i<=t1+1;i++){
            int xx=x+b*i/d,yy=y-a*i/d;
            if(abs(xx)+abs(yy)<ans || (abs(xx)+abs(yy)==ans && (a*abs(xx)+b*abs(yy))<(a*abs(x0)+b*abs(y0)))){
                x0=abs(xx),y0=abs(yy);
                ans=abs(xx)+abs(yy);
            }
        }
        for(int i=t2-1;i<=t2+1;i++){
            int xx=x+b*i/d,yy=y-a*i/d;
            if(abs(xx)+abs(yy)<ans || (abs(xx)+abs(yy)==ans && (a*abs(xx)+b*abs(yy))<(a*abs(x0)+b*abs(y0)))){
                x0=abs(xx),y0=abs(yy);
                ans=abs(xx)+abs(yy);
            }
        }printf("%d %d\n",x0,y0);
    }
    return 0;
} 

//方法二
#include <cstdio>
#include <algorithm>
using namespace std;
#define inf 0x7fffffff
int exgcd(int a,int b,int &x,int &y){
    if(!b){x=1,y=0;return a;}
    int c=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return c; 
}
int main(){
    freopen("poj2142.in","r",stdin);
    int a,b,c,x,y;
    while(scanf("%d%d%d",&a,&b,&c)>0 && (a||b||c)){
        int d=exgcd(a,b,x,y),t=c/d;
        int k=b/d;
        int x1=(x*t%k+k)%k;
        int y1=abs((a*x1-c)/b);

        exgcd(b,a,x,y);
        k=a/d;
        int x2=(x*t%k+k)%k;
        int y2=abs((b*x2-c)/a);

        if(x1+y1<x2+y2 || (x1+y1==x2+y2 && x1*a+b*y1<x2*b+y2*a)) printf("%d %d\n",x1,y1);
        else printf("%d %d\n",y2,x2);
    }
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/sunshiness_s/article/details/79830268