POJ 2142 The Balance 扩展欧几里德

7 篇文章 0 订阅
题意,给两种砝码,amg的和bmg的,和所称物品,dmg。
问怎样称,能使所用砝码数最少。如果有多种数量最少的方案,输出砝码总重量最小的方案

首先,显然是一个扩展欧几里德,求出a*x+b*y=gcd(a,b)的x和y的一组解,然后根据通解公式,找最小的|x|+|y|就行,从中选总重量最小的输出就好。
然后,就开始WA了,,,其实还是没有考虑全,对于gcd(a,b),它一定是<=min(a,b)的,当等于的时候,x和y肯定一个是0一个是1,当小于的时候,x和y必定一正一负。
所以,,,就通过通解,找到x的最小整数解,和最大负数解,然后一个向上枚举,一个向下枚举,就才能把所有的情况枚举完。。。
之前写的情况,是直接从那个解向上枚举和向下枚举,,这样,,就很可能两种情况都在同一边,然后就只会枚举到一种情况。。。

代码(很丑):
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
#define INF 99999999
int absi(int a)
{
	if (a >= 0)
		return a;
	else
		return -a;
}
int gcd(int a, int b)//普通方法
{
	int m, n, r;
	m = a >= b ? a : b;//m>=n
	n = a<b ? a : b;
	r = m%n;
	while (r != 0)
	{
		m = n;
		n = r;
		r = m%n;
	}
	return n;
}
int ex_gcd(int a, int b, int &x, int &y)
{
	int tmp, ans;
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	ans = ex_gcd(b, a%b, x, y);
	tmp = x;
	x = y;
	y = tmp - (a / b)*y;
	return ans;
}
int main()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	int a, b, c, d, x = 0, y = 0;
	bool ans = 0;
	while (scanf("%d%d%d", &a, &b, &d) != EOF && (a*b*d != 0))
	{
		x = 0, y = 0;
		c = gcd(a, b);
		ex_gcd(a, b, x, y);
		//printf("%d %d %d %d\n c %d d %d\n", a, b, x, y, c, d);
		int xa = d / c*x, ya = d / c*y, xb = d / c*x, yb = d / c*y;
		int xt = b / c, yt = a / c;
		//printf("%d %d\n", xa, ya);
		int tmp = xa / xt;

		xa = xa%xt;
		if (xa < 0)
		{
			xa += xt;
			ya += (tmp - 1)*yt;
		}
		else
		{
			ya += tmp*yt;
		}
		xb = xa - xt, yb = ya + yt;
		int suma = absi(xa) + absi(ya), sumb = absi(xb) + absi(yb);
		//printf("%d %d\n", xa, ya);
		//printf("%d %d\n", xb, yb);
		//printf("xt %d yt %d\n", xt, yt);
		//printf("%d %d\n", absi(xa - xt), absi(ya + yt));
		while (absi(xa - xt) + absi(ya + yt) < suma && (xa - xt > 0 || ya + yt > 0))
		{

			xa -= xt;
			ya += yt;
			suma = absi(xa) + absi(ya);
		}
		//printf("%d %d\n", xa, ya);
		int wa = absi(xa)*a + absi(ya)*b;
		//printf("%d %d\n", absi(xb + xt), absi(yb - yt));
		while (absi(xb + xt) + absi(yb - yt) < sumb && (xb + xt > 0 || yb - yt > 0))
		{
			xb += xt;
			yb -= yt;
			//printf("%d %d\n", xb, yb);
			sumb = absi(xb) + absi(yb);
		}
		//printf("%d %d\nans\n", xb, yb);
		int wb = absi(xb)*a + absi(yb)*b;
		if (suma < sumb)
			printf("%d %d\n", absi(xa), absi(ya));
		else if (sumb < suma)
			printf("%d %d\n", absi(xb), absi(yb));
		else if (wa < wb)
			printf("%d %d\n", absi(xa), absi(ya));
		else
			printf("%d %d\n", absi(xb), absi(yb));
	}
	//while (1);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值