【ybt金牌导航8-6-2】【POJ 2142】天平问题 / The Balance

天平问题 / 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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/114172844