The Balance(详细讲解)

 题目

        Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. For example, to measure 200mg of aspirin using 300mg weights and 700mg weights, she can put one 700mg weight on the side of the medicine and three 300mg weights on the opposite side (Figure 1). Although she could put four 300mg weights on the medicine side and two 700mg weights on the other (Figure 2), she would not choose this solution because it is less convenient to use more weights. 
You are asked to help her by calculating how many weights are required. 

        Iyo Kiffa-Australis 女士有一个天平,只有两种砝码来测量一剂药量。例如,要使用 300 毫克砝码和 700 毫克砝码测量 200 毫克阿司匹林,她可以将一个 700 毫克砝码放在药物一侧,将三个 300 毫克砝码放在另一侧(图 1)。虽然她可以在药物侧放四个 300mg 的砝码,另一侧放两个 700mg 的砝码(图 2),但她不会选择这种解决方案,因为使用更多的砝码不太方便。 
你被要求通过计算需要多少重量来帮助她。 

  输入

        输入是一系列数据集。数据集是包含三个正整数 a、b 和 d 的行,由空格分隔。以下关系成立:a != b、a <= 10000、b <= 10000 和 d <= 50000。您可以假设可以使用 a mg 和 b mg 权重的组合来测量 d mg。换句话说,您不需要考虑“无解决方案”的情况。 
输入的结尾由一行包含三个由空格分隔的零表示。它不是数据集。

 输出

        输出应由行组成,每行对应一个输入数据集 (a, b, d)。输出行应包含两个由空格分隔的非负整数 x 和 y。它们应满足以下三个条件。 

  • 您可以使用 x 个 amg 权重和 y 个 bmg 权重来测量 dmg。 
  • 权重总数 (x + y) 是满足上述条件的非负整数对中最小的。 
  • 在满足前两个条件的非负整数对中,权重的总质量 (ax + by) 是最小的。

输出中不应出现额外的字符(例如额外的空格)。

 样例输入

700 300 200
500 200 300
500 200 500
275 110 330
275 110 385
648 375 4002
3 1 10000
0 0 0

  样本输出

1 3
1 1
1 0
0 3
1 1
49 74
3333 1 

题目链接:The Balance 

思路

  • 该题要用扩展欧几里德算法,用exgcd可求得 a*x+b*y =gcd(a,b) 的一组特解 X=x和Y=y 

  • 于是该方程的解集合就是 X=x+k*b,Y=y-k*a(k为任意整数)

  • 使|X|+|Y|最小有两种情况:                                                                                                        1.若x>0,使x降至最小且大于0,利用关系式得出对应的y                                                          2.若y>0,使y降至最小且大于0,利用关系式得出对应的x

  • 最后判断两种情况

注:没有x<0和y<0的情况,因为d大于0且是gcd(a,b)的倍数

 完整代码

#include<iostream>
#include<cstdlib>     //abs函数
using namespace std;
typedef long long ll;
ll a,b,d,x,y;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0){x=1,y=0;return a;}
    ll res=exgcd(b,a%b,x,y);
    ll tmp=x;
    x=y;
    y=tmp-a/b*y;
    return res;
}
int main(){
    while (cin>>a>>b>>d&&(a+b+d)){
        ll gcd=exgcd(a,b,x,y);
        ll dx=b/gcd;         //当特解x>0时
        ll x1=(x*d/gcd%dx+dx)%dx;     //将x降至最小且大于0
        ll y1=abs(d-a*x1)/b;
        ll dy=a/gcd;         //当特解y>0时
        ll y2=(y*d/gcd %dy+dy)%dy;    //将y降至最小且大于0
        ll x2=abs(d-b*y2)/a;
        if(x1+y1>x2+y2||(x1+y1==x2+y2&&a*x1+b*y1>a*x2+b*y2)){      //只有这两种情况 |x|+|y| 是最小的,若相等再判断下乘积即可
            x1=x2;
            y1=y2;
        }
        cout<<x1<<" "<<y1<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_58177653/article/details/119297085