poj 2142 扩展欧几里得

本文介绍了解线性方程组ax+by=c的方法,并给出了一种求解通解的算法实现,通过枚举特定区间的变量i找到使得|x0-k1*i|+|y0-k2*i|达到最小值的整数解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ax+by=c;
求出通解x = xo + k1*i
       y = y0 - k2*i
k1,k2,你懂的.i是变量。
然后根据直线方程。
s = -x0/k1;
e = y0/k2;
min=min{s,e},max=max{s,e}
在区间[min-1,max+1]
这一段内,必取极小值。枚举这一段的 i
其中|x0 - k1 * i| + | y0 - k2*i| 在负无穷到s单调递减 e到正无穷单调递增
#include <iostream>
#include <algorithm>
#include <cstring>
#include <functional>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int NIL = -1;
const ll mod = 9973;
#define abs(a) ((a) > 0 ? (a) : (-1 * (a)))
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}


ll extgcd(ll a, ll b, ll &x, ll &y)
{
	if (b == 0)
	{
		x = 1, y = 0;
		return a;
	}
	ll xx, yy;
	ll ret = extgcd(b, a % b, xx, yy);
	x = yy;
	y = xx - (a / b) * yy;
	return ret;
}




int main(void)
{
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	ll a, b, c;
	while (cin >> a >> b >> c)
	{
		if (!a && !b && !c)
			return 0;
		ll x, y;
		ll g = extgcd(a, b, x, y);
		
		if (c % g == 0)
		{
			x *= c / g;
			y *= c / g;
			a /= g;
			b /= g;
			ll s = -x / b;
			ll e = y / a;
			
			ll ansx = abs(x), ansy = abs(y);
			for (ll t = min(s, e) - 1; t <= max(s, e) + 1; ++t)
			{
				if (ansx + ansy > abs(x + b * t) + abs(y - a * t))
					ansx = abs(x + b * t), ansy = abs(y - a * t);
				else if (ansx + ansy == abs(x + b * t) + abs(y - a * t))
				{
					if (a * ansx + b * ansy > a * abs(x + b * t) + b * abs(y - a * t))
						ansx = abs(x + b * t), ansy = abs(y - a * t);
				}
			}
			cout << ansx << " " << ansy << endl;
		}
		else
			cout << "-1" << endl;
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值