扩展欧几里得【HDU1356】

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1356

说实话,我第一眼没看出来是个exgcd(划掉)。

扩展欧几里得,这里就不证明了。

这次我想说的是怎么求不定方程得通解(这是七年级的题目,我怎么不记得我初一的时候学过不定方程?!)


上图片(滑稽)

求出通解以后,题目要求 求出abs(x)+abs(y)的最小值,为啥是abs(x)+abs(y)的最小值呢,因为,(x+y)和(ax+by)最小,而

a|x| = b|y| + c,所以如果x减小,那么也要减小。故转化为|x|+|y|最小。

我们保证a>b,那么|x|+|y|的单调性很容易看出|y|逼近于0的时候,整体答案是最小的。

(swap(a,b)之后,别忘把答案给swap回来,坑死我了)

代码代码:(那个for的意思是,把|y|为0的时候左右两边都看一眼)

#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9+7;
typedef long long ll;
ll x,y;
ll exgcd(ll &x,ll &y,int a,int b)
{
	ll d = a;
	if(b!=0)
	{
		d = exgcd(y,x,b,a%b);
		y -= (a/b)*x;
	}
	else
	{
		x = 1;
		y = 0;
	}
	return d;
}
int main()
{
	int a,b,d;
	while(cin>>a>>b>>d)
	{
		bool flag = false;
		if(a<b)
		{
			swap(a,b);
			flag = true;
		}
		if(a==0 && b==0 && d==0) break;
		ll k = d/exgcd(x,y,a,b);
		ll x0 = x*k, y0 = y*k;
		ll ansx = abs(x0),ansy = abs(y0);
		ll t = y0*(d/k)/a;
		for(int i=t-5;i<=t+5;i++)
		{
			ll tmpx = abs(x0+b/(d/k)*i);
			ll tmpy = abs(y0-a/(d/k)*i);
			if(abs(tmpx)+abs(tmpy)<abs(ansx)+abs(ansy))
			{
				ansx = tmpx;
				ansy = tmpy;
			}
		}
		if(flag)
		{
			swap(ansx,ansy);
		}
		cout<<ansx<<" "<<ansy<<endl;
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/83958775