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

题目

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


题解

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

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


代码

//方法一
#include 
#include 
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)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)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 
#include 
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*a+b*y1*b+y2*a)) printf("%d %d\n",x1,y1);
        else printf("%d %d\n",y2,x2);
    }
    return 0;
} 

你可能感兴趣的:(扩展欧几里德)