POJ2142 The Balance 不定方程求解

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


题目大意:现有一个天平和质量分别为a和b的砝码,已知砝码数量不限且天平左右均可放置砝码,要求在天平上称出质量为d的物品。找出一种可行的方案满足:放置的砝码数尽量少;在砝码数相同的情况下,砝码的总质量尽量小。


分析:我们设a,b砝码的数量分别为x和y,那么问题就转化为了求不定方程ax+by=d的一组整数解(x,y)满足|x|+|y|尽量小,在|x|+|y|相等的情况下a|x|+b|y|尽量小(x<0表示砝码和物品在同一侧)。

一种方法是:我们用扩展欧几里得可以求出方程的一个特解(x0,y0),进而可以得出方程的通解:x=x0+(b/d)*t;y=y0-(a/d)*t(t为正整数);我们不妨设a>b,那么|x|+|y|最小时,即|x0+(b/d)*t|+|y0-(a/d)*t|最小,另后一项为0,则得到t=y0*d/a,容易知道最终的解在t周围,我们可以枚举[ t-10,t+10 ]内的x,y值,从中找到最小的一组。



实现代码如下:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL a,b,c,d,x0,y0;
void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(!b)
    {
        x=1,y=0,d=a;
        return ;
    }
    else
    {
        exgcd(b,a%b,d,x,y);
        LL t=x;
        x=y;
        y=t-(a/b)*y;
    }
}
LL abs(LL x)
{
    return x>0?x:-x;
}
int main()
{
    while(scanf("%lld%lld%lld",&a,&b,&c))
    {
        if(a==0&&b==0&&c==0) break;
        bool flag=false;
        if(a<b)
        {
            flag=true;
            swap(a,b);
        }
        exgcd(a,b,d,x0,y0);
        x0=x0*(c/d);
        y0=y0*(c/d);
        LL t=y0*d/a,x,y;
        LL ans=999999999;
        for(LL i=t-10;i<=t+10;i++)
        {
            LL x1=x0+(b/d)*i;
            LL y1=y0-(a/d)*i;
            if(abs(x1)+abs(y1)<ans)
            {
                ans=abs(x1)+abs(y1);
                x=x1;
                y=y1;
            }
        }
        if(flag) printf("%lld %lld\n",abs(y),abs(x));
        else printf("%lld %lld\n",abs(x),abs(y));
    }
    return 0;
}




我们也可以这样考虑:要使|x|+|y|最小,无非是x取最小值或y取最小值,我们只需把这两个最小值分别找出来比较即可。


实现代码如下:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL a,b,c,d,x0,y0;
void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(!b)
    {
        x=1,y=0,d=a;
        return ;
    }
    else
    {
        exgcd(b,a%b,d,x,y);
        LL t=x;
        x=y;
        y=t-(a/b)*y;
    }
}
LL abs(LL x)
{
    return x>0?x:-x;
}
int main()
{
    while(scanf("%lld%lld%lld",&a,&b,&c))
    {
        if(a==0&&b==0&&c==0) break;
        exgcd(a,b,d,x0,y0);
        a/=d;b/=d;c/=d;
        LL x1=x0*c;
        x1=(x1%b+b)%b;
        LL y1=(c-a*x1)/b;
        //printf("x1=%lld y1=%lld\n",x1,y1);
        LL y2=y0*c;
        y2=(y2%a+a)%a;
        LL x2=(c-b*y2)/a;
        //printf("x2=%lld y2=%lld\n",x2,y2);
        if(x1+abs(y1)>abs(x2)+y2)
          printf("%lld %lld\n",abs(x2),y2);
        else printf("%lld %lld\n",x1,abs(y1));
    }
    return 0;
}


你可能感兴趣的:(POJ2142 The Balance 不定方程求解)