天平问题 / The Balance
题目链接:ybt金牌导航8-6-2 / POJ 2142
题目大意
给你一个天平和两种质量的砝码(无限个),然后问你如何秤出质量为一个给定值的商品。
保证可以秤出,要求用的砝码数量尽可能小,如果砝码数量相同,则要求所用砝码总质量尽可能小。
输出两个砝码所用的个数。
思路
首先我们想到,不可能有一种砝码在两边都出现。
因为如果这样,我们可以把左右两边各拿掉相同的个数,使得还是能秤出原来的质量,而且所用砝码个数和总质量也更优。
那我们就试着列一个式子:
a x + b y = c ax+by=c ax+by=c
( a , b a,b a,b 分别是两个砝码的质量)
( x , y x,y x,y 的绝对值是它们用的个数,如果是正数就是放在左边,否则就是放在右边)
( c c c 就是你要秤出的物品的质量)
那你发现它就是不定方程,那我们就用扩展欧几里得来解。
那因为题目规定一定有解,那不用管有没有解的情况。
然后我们考虑选最优的方案怎么选。
首先是砝码个数,那你想到肯定要有一个选的数量最小。
那你就把两边作为最小时另一边的值算出来。
然后比较一下哪个更优,就选哪个。
代码
#include<cstdio>
#define ll long long
using namespace std;
ll a, b, c, xy, yx;
ll x, y, ans1, ans2;
ll exgcd(ll a, ll &x, ll b, ll &y) {
//扩展欧几里得
if (!b) {
x = 1;
y = 0;
return a;
}
ll re = exgcd(b, y, a % b, x);
y -= a / b * x;
return re;
}
int main() {
scanf("%lld %lld %lld", &a, &b, &c);
while (a || b || c) {
ll gcd = exgcd(a, x, b, y);//算出通解
a /= gcd;
b /= gcd;
c /= gcd;
x = ((x * c) % b + b) % b;//之前除了c,现在乘回来
y = ((y * c) % a + a) % a;
xy = (c - x * a) / b;//算出x最小或y最小时另一个的值
yx = (c - y * b) / a;
if (xy < 0) xy = -xy;//小于0,说明是放在另一边,个数一样
if (yx < 0) yx = -yx;
if (x + xy < y + yx || ((x + xy == y + yx) && (a * x + b * xy < a * yx + b * y))) {
printf("%lld %lld\n", x, xy);//x最小的优
}
else {
printf("%lld %lld\n", yx, y);//y最小的优
}
scanf("%lld %lld %lld", &a, &b, &c);
}
return 0;
}