POJ 2142 The Balance (扩展欧几里德)

本文针对POJ 2142题目,介绍了一种利用扩展欧几里德算法求解最小砝码数量的方法。通过分析给定的砝码权值a、b及待称量的重量m,找到使用最少数量的砝码实现准确称量的方案。
题目:http://poj.org/problem?id=2142
题意:给你3个数a,b,m,其中a,b代表两种砝码的权值,m代表要称量的物品的重量。两种砝码分别用x,y个称出物品的重量,使得x+y最小,若有几种解,取ax+by最小的那组解。

分析:http://blog.youkuaiyun.com/w20810/article/details/43269303用扩展欧几里德求出特解(x0,y0)。设a>b,d=gcd(a,b),那么|x|+|y|=|x0+b/d*t|+|y0-a/d*t|,其中t为整数。在t=y0*d/a附近,使得|x|+|y|最小。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;
typedef long long LL;

LL my_abs(LL x)
{
	if(x<0)
		return -x;
	else
		return x;
}
void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
	if(b==0)
	{
		d=a;
		x=1;
		y=0;
	}
	else
	{
		exgcd(b,a%b,d,y,x);
		y-=x*(a/b);
	}
}

LL a,b;

struct node
{
	LL x,y;
	bool operator < (const node &t) const
	{
		if(x+y!=t.x+t.y)
			return x+y<t.x+t.y;
		else
			return a*x+b*y<t.x*a+t.y*b;
	}
}s[3];

int main()
{
	LL m,x,y,d;
	LL ansx,ansy;
	while(cin>>a>>b>>m,(a+b+m))
	{
		bool fg=0;
		if(a<b)
		{
			fg=1;
			swap(a,b);
		}
		exgcd(a,b,d,x,y);
		LL x0=x*m/d;
		LL y0=y*m/d;
			
		LL t=y0*d/a;

		s[0].x=my_abs(x0+b/d*(t-1));
		s[0].y=my_abs(y0-a/d*(t-1));
			
		s[1].x=my_abs(x0+b/d*(t));
		s[1].y=my_abs(y0-a/d*(t));
			
		s[2].x=my_abs(x0+b/d*(t+1));
		s[2].y=my_abs(y0-a/d*(t+1));
		
		sort(s,s+3);
			
		ansx=s[0].x;
		ansy=s[0].y;
			
		if(!fg)
			cout<<ansx<<" "<<ansy<<"\n";
		else
			cout<<ansy<<" "<<ansx<<"\n";
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值