Poj2142解不定方程——一元线性同余

题意:有一天平质量为ab的砝码已知砝码数量不限且天平左右均可以放砝码,现在要求用天平称出c的物品各需要多少

解析:转化为ax+by=c的一组整数解(xy)要求|x|+|y|尽量小

利用扩展欧几里得求出特解x0 和 y0然后给出通项公式

x=x0+a/d*t    

y=y0+b/d*t

  对于方程的全部解x=x0+(a/d)t   y=y0+(b/d)*t
   |x|+|y|= | x + b/g*t | + | y - a/g*t |    
    这个关于t的函数的最小值应该在|y - a/g*t|为零附近,即t=y*g/a
    在 y*g/a 附近的两整数点里取t,再直接验证这两点即可。 
   

#include<iostream>
using namespace std;
typedef long long ll;
__int64 ABS(__int64 x)
{
	if(x<0)
	return -x;
	return x;
}
void exgcd(ll a,ll b,ll &x,ll &y,ll &d)
{
	if(!b)
	{
		d=a;
		x=1;
		y=0;
	}
	else
	{
		exgcd(b,a%b,y,x,d);
		y-=x*(a/b);
	}
}
int main()
{
	ll a,b,c,d,sub;
	while(scanf("%I64d%I64d%I64d",&a,&b,&c)!=EOF && a+b+c)
	{
		bool ifsub=0;
		if(a<b)
		{
			ifsub=1;
			sub=a;
			a=b;
			b=sub;
		}
		/*所以方程 a*x+b*y=n;我们可以先用扩展欧几里德算法求出一组x0,y0。
		也就是a*x0+b*y0=gcd(a,b);然后两边同时除以(a,b),
		再乘以n。这样就得到了方程a*x0*n/(a,b)+b*y0*n/(a,b)=n;
		我们也就找到了方程的一个解。
		所以此处不用mod b 但是对于同余方程有些地方是要求mod b的 这里纠结了我好久啊
		 
		*/
		 
		ll x0,y0,d;
		exgcd(a,b,x0,y0,d);
		x0*=(c/d);
		y0*=(c/d);
		ll t=y0*d/a;
		/*对于方程的全部解x=x0+(a/d)t   y=y0+(b/d)*t
		| |x|+|y|= | x + b/g*t | + | y - a/g*t |     
		  这个关于t的函数的最小值应该在|y - a/g*t|为零附近,即t=y*g/a 
		  在 y*g/a 附近的两整数点里取t,再直接验证这两点即可。 
 		*/ 
		ll min=0x7ffffff,ans,anst;
		for(ll i=t-10;i<=t+10;i++)
		{
			if(ABS((x0+b/d*i))+ABS((y0-a/d*i))<min)
			{
				ans=a*ABS(x0+b/d*i)+b*ABS(y0-a/d*i);
				anst=i;
				min=ABS(x0+b/d*i)+ABS(y0-a/d*i);
				
			}
			else
			if(ABS(x0+b/d*i)+ABS(y0-a/d*i)==min)
			{
				if(a*ABS(x0+b/d*i)+b*ABS(y0-a/d*i)<ans)
				{
					ans=a*ABS(x0+b/d*i)+b*ABS(y0-a/d*i);
					anst=i;
					min=ABS(x0+b/d*i)+ABS(y0-a/d*i);
				}
			}
		}
		if(!ifsub)
		{
			printf("%I64d %I64d\n",ABS(x0+b/d*anst),ABS(y0-a/d*anst));
		}
		else
		{
			printf("%I64d %I64d\n",ABS(y0-a/d*anst),ABS(x0+b/d*anst));
		}
	}
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值