1. 程式人生 > >擴充套件歐幾里得【HDU1356】

擴充套件歐幾里得【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;
}