POJ-2142(扩展欧几里德+同余方程)(The Balance )

方法一:

/*==========================================================*\
| [扩展眼欧几里德]给定 a b d找到满足ax+by=d 的令|x|+|y|最小
| 参考线性同余方程 g=gcd(a,b) , ax0+by0=gcd(a,b)
| 程的一组解: x=x0*d/g; y=y0*d/g;   
| 方程的全部解:x..=x+b/g*t   y..=y-a/g*t
| |x|+|y|= | x + b/g*t | + | y - a/g*t |    
| 这个关于t的函数的最小值应该在|y - a/g*t|为零附近,即t=y*g/a
| 在 y*g/a 附近的两整数点里取t,再直接验证这两点即可。
\*==========================================================*/
int extended_gcd(int a, int b, int & x, int & y)
{
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int d = extended_gcd(b, a % b, x, y);
	int t = x;
	x = y;
	y = t - a / b * y;
	return d;
}
int main()
{
	int a, b, d;
	while (scanf("%d%d%d", &a, &b, &d) == 3 && (a || b || d)) {
		int tag = 1;
		int x0, y0;
		if (a < b) {
			tag = 0;
			swap(a, b);
		}
		int g = extended_gcd(a, b, x0, y0);
		int x = x0 * d / g;
		int y = y0 * d / g;
		int t1 = y * g / a;
		if (t1 * a / g - y >= 0) --t1;
		int t2 = t1 + 1;
		int x1 = MY_ABS(x + b / g * t1);
		int y1 = MY_ABS(y - a / g * t1);
		int x2 = MY_ABS(x + b / g * t2);
		int y2 = MY_ABS(y - a / g * t2);
		if ((x1 + y1 > x2 + y2) || ((x1 + y1 == x2 + y2) && (a * x1 + b * y1 > a * x2 + b * y2))) {//当(|x|+|y|)相等时,比较(a|x|+b|y|)哪个小
			if (tag) printf("%d %d\n", x2, y2);
			else printf("%d %d\n", y2, x2);
		} else {
			if (tag) printf("%d %d\n", x1, y1);
			else printf("%d %d\n", y1, x1);
		}
	}
    return 0;
}
方法二:

有三种情况:
ax+by=d;(a,b均在左盘)
ax-by=d;(a在左盘,b和d在右盘)
-ax+by=d;(b在左盘,a和d在右盘)
枚举a,求满足条件的解。
#include<iostream>
#include
<cmath>
using namespace std;
int main()
{
    
int i,a,b,d,x,y,xx,yy;
    
int sum1,sum2;
    
while(cin>>a>>b>>d)
    
{
        
if(a==0 && b==0 && d==0)break;
        
int min1=9000000,min2=9000000;
        
int t=0;
        xx
=0;yy=0;
        
for(i=0; ; i++){
            
if((d-a*i)%b==0)//ax+by=d 和 ax-by=d 两种情况,用绝对值表示,所以合写成一个if 
            {
                yy
=abs((d-a*i)/b);
                sum1
=i+yy;
                sum2
=a*i+b*yy;
                
if(sum1<min1)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
else if(sum1==min1 && sum2<min2)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
if(i>min1 || i*a>min2)//如果x的值比x+y的值都大或者a*x比a*x+b*y 的值都大了就跳出 
                    break;
            }

            
int l=i*a+d;
            
if(l>0 && l%b==0)//-ax+by=d的情况 
            {
                yy
=l/b;    
                sum1
=i+yy;
                sum2
=a*i+b*yy;
                
if(sum1<min1)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
else if(sum1==min1 && sum2<min2)
                    min1
=sum1,min2=sum2,x=i,y=yy;
                
if(i>min1 || i*a>min2)//如果x的值比x+y的值都大或者a*x比a*x+b*y 的值都大了就跳出
                    break;
                
            }

        }


        cout
<<x<<" "<<y<<endl;

    }


return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值