题目意思一开始没理解,原来是 给你重为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;
但是 题目要求是正的 这时候 就是考验对扩展欧几里德了解程度了 下面贴出关于这部分的性质:
先求出最小正解的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; } }