poj2142 The Balance 扩展欧几里德的应用 稍微还是有点难度的

题目意思一开始没理解,原来是 给你重为a,b,的砝码 求测出 重量为d的砝码,a,b砝码可以无限量使用


开始时我列出来三个方程 :

a*x+b*y=d;

a*x-b*y=d;

b*y-ax=d;

傻眼了,可是我们知道 x,y前面的正负符号是不影响extgcd的使用的,比如poj1061 方程式是 px+qy=m,而 nefu84方程式是:px-qy=m;

所以不影响 只是方法没有想好,后来想到了  先令ax+by=1,求解出 x,y再乘以d不就可以了吗?

一开始 球ax+by=1时 我居然直接使用了 extgcd ,然后解出x0,y0,则x=x0*1/gcd值,可是这道题目的 a,b的gcd不一定为1,所以1/gcd会等于0,所以 这道题目一定要先求出a,b,的gcd值,然后 a/=gcd,b/=gcd,d/=gcd,这样 再求出x,y,的值 就不需要再乘以 1/gcd啦,好开心 感觉越做自信越高了

接下里 的话 题目 对于 x,y是有要求 的  要x+y尽量小,ax+by尽量小,你求出的 x,y中有可能的是有负的,那很正常,因为题目要求的是测出d的重量,所以 有可能是

a*x+b*y=d;

a*x-b*y=d;

b*y-ax=d;

但是 题目要求是正的 这时候 就是考验对扩展欧几里德了解程度了 下面贴出关于这部分的性质:

 

对于不定整数方程pa+qb=c,若 c mod Gcd(a, b)=0,则该方程存在整数解,否则不存在整数解。
上面已经列出找一个 整数解的方法,在找到p * a+q * b = Gcd(a, b)的一组解p0,q0后, /*p * a+q * b = Gcd(a, b)的其他整数解满足:
p = p0 + a/Gcd(a, b) * t
q = q0 - b/Gcd(a, b) * t(其中t为任意 整数)
至于pa+qb=c的整数解,只需将p * a+q * b = Gcd(a, b)的每个解乘上 c/Gcd(a, b) 即可
在找到p * a+q * b = Gcd(a, b)的一组解p0,q0后,应该是
得到p * a+q * b = c的一组解p1 = p0*(c/Gcd(a,b)),q1 = q0*(c/Gcd(a,b)),p * a+q * b = c的其他整数解满足:
p = p1 + b/Gcd(a, b) * t
q = q1 - a/Gcd(a, b) * t(其中t为任意 整数)
p 、q就是p * a+q * b = c的所有 整数解。
就是运用扩展欧几里德求出 的 p,q给的是最小的那一组 有可能是负的 而题目 明显要求了 x不能为负,所以要利用上述性质 来求出最小 正解

 

 

先求出最小正解的x1然后利用式子 y1=(d-a*x1)/b;

然后 求出 最小正解 y2,然后利用式子x2=(d-b*y2)/a;

然后 比较 x1+y1 x2+y2的大小  取小的那一组

 

#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>

#define ll long long
#define LL __int64
#define eps 1e-8

const ll INF=9999999999999;

#define M 400000100

#define inf 0xfffffff

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int> P;
//vector<pair<int,int>> ::iterator iter;
//
//map<ll,int>mp;
//map<ll,int>::iterator p;
//
//vector<int>G[30012];

ll GCD(ll a,ll b)
{
	while(b)
	{
		ll r=b;
		b=a%b;
		a=r;
	}
	return a;
}

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

int main(void)
{
	ll a,b,d;
	while(cin>>a>>b>>d)
	{
		if(a+b+d == 0)
			break;
		ll x0,y0;
		ll gcd=GCD(a,b);//这里要先求出 a,b的gcd值
		a/=gcd;
		b/=gcd;
		d/=gcd;//都除以gcd
		extgcd(a,x0,b,y0);
		ll x=x0*d;
		ll y=y0*d;//求出的 x0就不需要 乘以1/gcd 了,
		ll x1=x,y1=y;
		x1=(x%b+b)%b;//这里是假设不知道x,y的正负情况,求出x1的最小正解
		y1=(d-x1*a)/b;//对应x1的y1最小正解
		if(y1<0)
			y1=0-y1;
		ll x2=x,y2=y;
		y2=(y2%a+a)%a;//这里是假设不知道x,y的正负情况,求出y2的最小正解
		x2=(d-y2*b)/a;//对应x2的y1最小正解
		if(x2<0)
			x2=0-x2;
		if(x1+y1 > x2+y2)//比较 x1+y1 x2+y2的大小
			x=x2,y=y2;
		else
			x=x1,y=y1;
		cout<<x<<" "<<y<<endl;
	}
}


 


 

你可能感兴趣的:(poj)